You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openaz.apache.org by pd...@apache.org on 2016/03/17 02:15:41 UTC

[19/23] incubator-openaz git commit: Ported original att source to openaz This Closes #3

http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/648d0c0d/openaz-xacml-pap-admin/src/main/java/org/apache/openaz/xacml/admin/components/PolicyEditor.java
----------------------------------------------------------------------
diff --git a/openaz-xacml-pap-admin/src/main/java/org/apache/openaz/xacml/admin/components/PolicyEditor.java b/openaz-xacml-pap-admin/src/main/java/org/apache/openaz/xacml/admin/components/PolicyEditor.java
new file mode 100644
index 0000000..f6ab0f8
--- /dev/null
+++ b/openaz-xacml-pap-admin/src/main/java/org/apache/openaz/xacml/admin/components/PolicyEditor.java
@@ -0,0 +1,1679 @@
+/*
+ *  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.components;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
+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.MatchType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.VariableDefinitionType;
+
+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.model.GitRepositoryContainer;
+import org.apache.openaz.xacml.admin.model.PolicyContainer;
+import org.apache.openaz.xacml.admin.util.AdminNotification;
+import org.apache.openaz.xacml.admin.util.JPAUtils;
+import org.apache.openaz.xacml.admin.view.windows.AttributeSelectionWindow;
+import org.apache.openaz.xacml.admin.view.windows.AttributeValueEditorWindow;
+import org.apache.openaz.xacml.admin.view.windows.ExpressionBuilderComponent;
+import org.apache.openaz.xacml.admin.view.windows.MatchEditorWindow;
+import org.apache.openaz.xacml.admin.view.windows.ObligationAdviceEditorWindow;
+import org.apache.openaz.xacml.admin.view.windows.PolicyEditorWindow;
+import org.apache.openaz.xacml.admin.view.windows.PolicySetEditorWindow;
+import org.apache.openaz.xacml.admin.view.windows.RuleEditorWindow;
+import org.apache.openaz.xacml.admin.view.windows.VariableDefinitionEditorWindow;
+import org.apache.openaz.xacml.util.XACMLObjectCopy;
+import org.apache.openaz.xacml.util.XACMLPolicyWriter;
+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.DataBoundTransferable;
+import com.vaadin.event.ItemClickEvent;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.event.ShortcutAction;
+import com.vaadin.event.dd.DragAndDropEvent;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.acceptcriteria.AcceptAll;
+import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
+import com.vaadin.server.BrowserWindowOpener;
+import com.vaadin.server.FileDownloader;
+import com.vaadin.server.StreamResource;
+import com.vaadin.shared.ui.dd.VerticalDropLocation;
+import com.vaadin.ui.AbstractSelect.AbstractSelectTargetDetails;
+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.CustomComponent;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.TabSheet.Tab;
+import com.vaadin.ui.Table.TableDragMode;
+import com.vaadin.ui.TreeTable;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window.CloseEvent;
+import com.vaadin.ui.Window.CloseListener;
+
+public class PolicyEditor extends CustomComponent {
+	/*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */
+
+	@AutoGenerated
+	private VerticalLayout mainLayout;
+
+	@AutoGenerated
+	private TreeTable tree;
+
+	@AutoGenerated
+	private HorizontalLayout horizontalLayoutToolbar;
+
+	@AutoGenerated
+	private Button buttonExport;
+
+	@AutoGenerated
+	private Button buttonViewXML;
+
+	@AutoGenerated
+	private Button buttonSave;
+
+	@AutoGenerated
+	private CheckBox checkBoxAutoSave;
+
+	@AutoGenerated
+	private CheckBox checkBoxReadOnly;
+
+	private static final long serialVersionUID = 1L;
+	private static Log logger	= LogFactory.getLog(PolicyEditor.class);
+	private final PolicyEditor self = this;
+
+	private static final Action CREATE_POLICY =			new Action ("New Policy");
+	private static final Action CREATE_POLICYSET =		new Action ("New Policy Set");
+	private static final Action CREATE_RULE =			new Action ("New Rule");
+	private static final Action EDIT_POLICY =			new Action ("Edit Policy");
+	private static final Action EDIT_POLICYSET =		new Action ("Edit Policy Set");
+	private static final Action EDIT_RULE =				new Action ("Edit Rule");
+	private static final Action DELETE_POLICYSET =		new Action ("Delete Policy Set");
+	private static final Action DELETE_POLICY = 		new Action ("Delete Policy");
+	private static final Action DELETE_RULE = 			new Action ("Delete Rule");
+	private static final Action CREATE_NEWANYOF =		new Action ("New Any Of (Match)");
+	private static final Action CREATE_NEWALLOF =		new Action ("New All Of (Match)");
+	private static final Action CREATE_NEWMATCH =		new Action ("New Match");
+	private static final Action DELETE_ANYOF =			new Action ("Delete Any Of");
+	private static final Action DELETE_ALLOF =			new Action ("Delete All Of");
+	private static final Action DELETE_MATCH =			new Action ("Delete Match");
+	private static final Action EDIT_MATCH =			new Action ("Edit Match");
+	private static final Action EDIT_OBLIGATIONS =		new Action ("Edit Obligations");
+	private static final Action DELETE_OBLIGATIONS = 	new Action ("Delete Obligations");
+	private static final Action EDIT_ADVICE =			new Action ("Edit Advice");
+	private static final Action DELETE_ADVICE = 		new Action ("Delete Advice");
+	private static final Action CREATE_VARIABLE =		new Action ("Create Variable");
+	private static final Action EDIT_VARIABLE =			new Action ("Edit Variable");
+	private static final Action DELETE_VARIABLE =		new Action ("Delete Variable");
+	private static final Action CREATE_TARGET = 		new Action ("Create Target");
+	private static final Action CREATE_CONDITION =		new Action ("Create Condition");
+	private static final Action EDIT_CONDITION =		new Action ("Edit Condition");
+	private static final Action DELETE_CONDITION =		new Action ("Delete Condition");
+	private static final Action EDIT_EXPRESSIONS =		new Action ("Edit Expressions");
+	
+	private static final Action CLIPBOARD_CUT =			new ShortcutAction ("Cut", ShortcutAction.KeyCode.S, new int[] {ShortcutAction.ModifierKey.CTRL});
+	private static final Action CLIPBOARD_COPY =		new ShortcutAction ("Copy", ShortcutAction.KeyCode.C, new int[] {ShortcutAction.ModifierKey.CTRL});
+	private static final Action CLIPBOARD_PASTE = 		new ShortcutAction ("Paste", ShortcutAction.KeyCode.V, new int[] {ShortcutAction.ModifierKey.CTRL});
+
+	private static final Object[] VISIBLE_COLUMNS = new Object[] {PolicyContainer.PROPERTY_NAME, PolicyContainer.PROPERTY_SHORTALGORITHM, PolicyContainer.PROPERTY_DESCRIPTION};
+	private static final String[] COLUMN_HEADERS = new String[] { "Name", "Algorithm or Effect", "Description"};
+
+	private final File file;
+	private final GitRepositoryContainer gitContainer;
+	private final PolicyContainer policyContainer;
+	private Tab tab = null;
+	private boolean isModified = false;
+	
+	private Object clipboardObject = null;
+
+	/**
+	 * 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.
+	 * @throws IOException 
+	 */
+	public PolicyEditor(File policyFile, GitRepositoryContainer gitContainer, boolean readOnly) throws IOException {
+		buildMainLayout();
+		setCompositionRoot(mainLayout);
+		this.mainLayout.setSizeFull();
+		//
+		// Save
+		//
+		this.file = policyFile;
+		this.gitContainer = gitContainer;
+		this.policyContainer = new PolicyContainer(this.file);
+		//
+		// Its our data also
+		//
+		this.setData(policyFile);
+		//
+		// Initialize GUI
+		//
+		this.initializeCheckboxes(readOnly);
+		this.initializeButtons();
+		this.initializeDownload();
+		this.initializeTree();
+// PLD TODO next release		this.initializeContextMenu();
+		//
+		// setup the caption etc.
+		//
+		this.setupCaption();
+		this.resetComponents();
+	}
+	
+	protected void initializeCheckboxes(boolean readOnly) {
+		//
+		// The readonly check box
+		//
+		this.checkBoxReadOnly.setImmediate(true);
+		this.checkBoxReadOnly.setValue(readOnly);
+		this.checkBoxReadOnly.addValueChangeListener(new ValueChangeListener() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void valueChange(ValueChangeEvent event) {
+				self.resetComponents();
+				self.setupCaption();
+			}
+			
+		});
+		//
+		// The autosave check box
+		//
+		this.checkBoxAutoSave.setImmediate(true);
+		this.checkBoxAutoSave.setValue(true);
+	}
+	
+	protected void initializeButtons() {
+		//
+		// The Save button
+		//
+		this.buttonSave.addClickListener(new ClickListener() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void buttonClick(ClickEvent event) {
+				self.savePolicy();
+			}
+		});
+		//
+		// Attach a window opener to the View XML button
+		//
+		BrowserWindowOpener opener = new BrowserWindowOpener(new StreamResource(new StreamResource.StreamSource() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public InputStream getStream() {
+				try {
+					if (logger.isDebugEnabled()) {
+						logger.debug("Setting view xml button to: " + self.file.getAbsolutePath());
+					}
+					return new FileInputStream(self.file);
+				} catch (Exception e) {
+					logger.error("Failed to open input stream " + self.file);
+				}
+				return null;
+			}
+		}, self.file.getName()));
+		opener.setWindowName("_new");
+		opener.extend(this.buttonViewXML);
+	}
+	
+	protected void initializeDownload() {
+		//
+		// Create a stream resource pointing to the file
+		//
+		StreamResource r = new StreamResource(new StreamResource.StreamSource() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public InputStream getStream() {
+				try {
+					return new FileInputStream(self.file);
+				} catch (Exception e) {
+					logger.error("Failed to open input stream " + self.file);
+				}
+				return null;
+			}
+		}, self.file.getName());
+		r.setCacheTime(-1);
+		r.setMIMEType("application/xml");
+		//
+		// Extend a downloader to attach to the Export Button
+		//
+		FileDownloader downloader = new FileDownloader(r);
+		downloader.extend(this.buttonExport);
+	}
+	
+	public void setTab(Tab tab) {
+		this.tab = tab;
+		this.setupCaption();
+	}
+	
+	public boolean isAutoSave() {
+		if (this.checkBoxAutoSave.isEnabled() == false) {
+			return false;
+		}
+		return this.checkBoxAutoSave.getValue();
+	}
+	
+	public boolean isReadOnly() {
+		return this.checkBoxReadOnly.getValue();
+	}
+
+	protected void initializeTree() {
+		//
+		// Create our container and set it as the tree's data source
+		//
+		this.tree.setContainerDataSource(this.policyContainer);
+		this.tree.setItemIconPropertyId("Icon");
+		this.tree.setVisibleColumns(VISIBLE_COLUMNS);
+		this.tree.setColumnHeaders(COLUMN_HEADERS);
+		this.tree.setSelectable(true);
+		this.tree.setSizeFull();
+		//
+		// Expand it down a few items
+		//
+		for (Object id : this.tree.getItemIds()) {
+			this.tree.setCollapsed(id, false);
+			for (Object child : this.tree.getChildren(id)) {
+				this.tree.setCollapsed(child, false);
+			}
+		}
+		//
+		// Respond to double-click's
+		//
+		this.tree.addItemClickListener(new ItemClickListener() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void itemClick(ItemClickEvent event) {
+				if (event.isDoubleClick()) {
+					if (self.isReadOnly()) {
+						AdminNotification.info("You are in read-only mode.");
+						return;
+					}
+					Object target = event.getItemId();
+					if (target instanceof PolicySetType) {
+						self.editPolicySet((PolicySetType) target, (PolicySetType) self.policyContainer.getParent(target));
+					} else if (target instanceof PolicyType) {
+						self.editPolicy((PolicyType) target, (PolicySetType) self.policyContainer.getParent(target));
+					} else if (target instanceof RuleType) {
+						self.editRule((RuleType) target, (PolicyType) self.policyContainer.getParent(target));
+					} else if (target instanceof ConditionType) {
+						self.editCondition((ConditionType) target, (RuleType) self.policyContainer.getParent(target));
+					} else if (target instanceof VariableDefinitionType) {
+						self.editVariable((VariableDefinitionType) target, (PolicyType) self.policyContainer.getParent(target));
+					} else if (target instanceof MatchType) {
+						self.editMatch((MatchType) target, (AllOfType) self.policyContainer.getParent(target), null, null, "Edit Match");
+					} else if (target instanceof ObligationExpressionType) {
+						self.editObAdvice(true, self.policyContainer.getParent(target));
+					} else if (target instanceof AdviceExpressionType) {
+						self.editObAdvice(false, self.policyContainer.getParent(target));
+					}
+				}
+			}
+			
+		});
+		//
+		// Respond to container changes
+		//
+		this.policyContainer.addItemSetChangeListener(new ItemSetChangeListener() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void containerItemSetChange(ItemSetChangeEvent event) {
+				self.isModified = true;
+				if (self.isAutoSave()) {
+					self.savePolicy();
+				} else {
+					self.setupCaption();
+					self.buttonSave.setEnabled(true);
+				}
+			}
+		});
+		//
+		// Implement drag-n-drop
+		//
+		this.tree.setDropHandler(new DropHandler() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void drop(DragAndDropEvent event) {
+				DataBoundTransferable t = (DataBoundTransferable) event.getTransferable();
+			    AbstractSelectTargetDetails target = (AbstractSelectTargetDetails) event.getTargetDetails();
+			    
+			    //
+			    // Get ids of the dragged item and the target item
+			    //
+			    Object sourceItemId = t.getData("itemId");
+				Object targetItemId = target.getItemIdOver();
+				VerticalDropLocation location = target.getDropLocation();
+				if (logger.isDebugEnabled()) {
+					logger.debug("Drop " + sourceItemId + " target " + targetItemId + " location " + location);
+				}
+				//
+				// Tell our container what to do
+				//
+				try {
+					if (location == VerticalDropLocation.MIDDLE) {
+						//
+						// Drop right on top of item making it a child
+						//
+						self.policyContainer.setParent(sourceItemId, targetItemId);
+					}
+
+					/*
+					} else if (location == VerticalDropLocation.TOP) {
+						//
+						// Drop at the top of the tree making it the previous
+						//
+						Object parent = self.policyContainer.getParent(targetItemId);
+						self.policyContainer.setParent(sourceItemId, parent);
+						self.policyContainer.moveAfterSibling(sourceItemId, targetItemId);
+						self.policyContainer.moveAfterSibling(targetItemId, sourceItemId);
+					} else if (location == VerticalDropLocation.BOTTOM) {
+						//
+						// Drop below another item
+						//
+						Object parent = self.policyContainer.getParent(targetItemId);
+						self.policyContainer.setParent(sourceItemId, targetItemId);
+						self.policyContainer.moveAfterSibling(sourceItemId, targetItemId);
+					}
+					*/
+				} catch (UnsupportedOperationException e) {
+					logger.error("Unsupported " + e.getLocalizedMessage());
+				}
+			}
+
+			@Override
+			public AcceptCriterion getAcceptCriterion() {
+				return AcceptAll.get();
+			}
+		});
+	}
+	
+	protected void removeObject(Object target) {
+		if (target instanceof PolicySetType) {
+			this.removePolicySet((PolicySetType) target);
+		} else if (target instanceof PolicyType) {
+			this.removePolicy((PolicyType) target);
+		} else if (target instanceof RuleType) {
+			this.removeRule((RuleType) target);
+		} else if (target instanceof ConditionType) {
+			this.removeCondition((ConditionType) target);
+		} else if (target instanceof VariableDefinitionType) {
+			this.removeVariable((VariableDefinitionType) target);
+		} else if (target instanceof AdviceExpressionType) {
+			this.removeAdvice((AdviceExpressionType) target);
+		} else if (target instanceof ObligationExpressionType) {
+			this.removeObligations((ObligationExpressionType) target);
+		}
+	}
+
+	protected void removeAdvice(AdviceExpressionType target) {
+		if (this.tree.removeItem(target) == false) {
+			logger.error("Failed to remove advice.");
+		}
+	}
+
+	protected void removeVariable(VariableDefinitionType target) {
+		if (this.tree.removeItem(target) == false) {
+			logger.error("Failed to remove variable.");
+		}
+	}
+
+	protected void removeCondition(ConditionType target) {
+		if (this.tree.removeItem(target) == false) {
+			logger.error("Failed to remove condition.");
+		}
+	}
+
+	protected void removeObligations(ObligationExpressionType target) {
+		if (this.tree.removeItem(target) == false) {
+			logger.error("Failed to remove obligations.");
+		}
+	}
+
+	protected void removeRule(RuleType target) {
+		if (this.tree.removeItem(target) == false) {
+			logger.error("Failed to remove rule.");
+		}
+	}
+
+	protected void removePolicy(PolicyType target) {
+		Object parent = this.tree.getParent(target);
+		if (parent == null) {
+			this.deleteRoot(target);
+		} else {
+			if (this.tree.removeItem(target) == false) {
+				logger.error("Failed to remove policy.");
+			}
+		}
+	}
+
+	protected void removePolicySet(PolicySetType target) {
+		Object parent = this.tree.getParent(target);
+		if (parent == null) {
+			this.deleteRoot(target);
+		} else {
+			if (this.tree.removeItem(target) == false) {
+				logger.error("Failed to remove policy set.");
+			}
+		}
+	}
+
+	/*
+	protected void initializeContextMenu() {
+		ContextMenu menu = new ContextMenu();
+		menu.setAsTableContextMenu(this.tree);
+		menu.addContextMenuTableListener(new TableListener() {
+
+			@Override
+			public void onContextMenuOpenFromFooter(
+					ContextMenuOpenedOnTableFooterEvent event) {
+				// TODO Auto-generated method stub
+				
+			}
+
+			@Override
+			public void onContextMenuOpenFromHeader(
+					ContextMenuOpenedOnTableHeaderEvent event) {
+				// TODO Auto-generated method stub
+				
+			}
+
+			@Override
+			public void onContextMenuOpenFromRow(ContextMenuOpenedOnTableRowEvent event) {
+				logger.info("context menu row");
+			}
+		});
+		menu.addItem("test");
+	}
+	*/
+	
+	protected void savePolicy() {
+		if (this.isReadOnly()) {
+			logger.warn("Should not call savePolicy when in read only mode.");
+			return;
+		}
+		Collection<?> roots = this.policyContainer.rootItemIds();
+		if (roots.size() > 1) {
+			logger.warn("More than one root policy.");
+		}
+		//
+		// There should only be one root
+		// Save the policy to disk.
+		//
+		for (Object root : roots) {
+			logger.info("Saving policy: " + this.file.getName());
+			//
+			// TODO - Bump the version?
+			//
+			if (root instanceof PolicySetType) {
+				XACMLPolicyWriter.writePolicyFile(Paths.get(this.file.getAbsolutePath()), (PolicySetType) root);
+			} else if (root instanceof PolicyType) {
+				XACMLPolicyWriter.writePolicyFile(Paths.get(this.file.getAbsolutePath()), (PolicyType) root);
+			}
+			//
+			// TODO ????
+			//
+			this.gitContainer.updateItem(this.file);
+			break; // NOPMD
+		}
+		//
+		// No longer modified
+		//
+		this.isModified = false;
+		this.setupCaption();
+		this.resetComponents();
+	}
+	
+	protected void installTreeActionHandler() {
+		//
+		// Remove any existing action handlers
+		//
+		this.tree.removeAllActionHandlers();
+		//
+		// Are we read-only?
+		//
+		if (this.isReadOnly()) {
+			//
+			// Yes - no action handler's allowed
+			//
+			return;
+		}
+		//
+		// Setup our action handlers
+		//
+		this.tree.addActionHandler(new Handler() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public Action[] getActions(Object target, Object sender) {
+				//
+				// Are we read-only?
+				//
+				if (self.isReadOnly()) {
+					if (logger.isDebugEnabled()) {
+						logger.debug("Policy is read-only");
+					}
+					return null;
+				}
+				if (target == null) {
+					//
+					// Nothing is selected, they right-clicked empty space
+					//
+					if (logger.isDebugEnabled()) {
+						logger.debug("action tree target is null");
+					}
+					return null;
+				}
+				if (target instanceof PolicySetType) {
+					List<Action> actions = new ArrayList<Action>();
+					actions.add(EDIT_POLICYSET);
+					if (((PolicySetType) target).getTarget() == null) {
+						actions.add(CREATE_TARGET);
+					}
+					/*
+					actions.add(CLIPBOARD_CUT);
+					actions.add(CLIPBOARD_COPY);
+					actions.add(CLIPBOARD_PASTE);
+					*/
+					actions.add(CREATE_POLICYSET);
+					actions.add(CREATE_POLICY);
+					actions.add(EDIT_OBLIGATIONS);
+					actions.add(EDIT_ADVICE);
+					actions.add(DELETE_POLICYSET);
+					return (Action[]) actions.toArray(new Action[0]);
+				}
+				if (target instanceof PolicyType) {
+					List<Action> actions = new ArrayList<Action>();
+					actions.add(EDIT_POLICY);
+					if (((PolicyType) target).getTarget() ==  null) {
+						actions.add(CREATE_TARGET);
+					}
+					/*
+					actions.add(CLIPBOARD_CUT);
+					actions.add(CLIPBOARD_COPY);
+					actions.add(CLIPBOARD_PASTE);
+					*/
+					actions.add(CREATE_RULE);
+					actions.add(CREATE_VARIABLE);
+					actions.add(EDIT_OBLIGATIONS);
+					actions.add(EDIT_ADVICE);
+					actions.add(DELETE_POLICY);
+					return (Action[]) actions.toArray(new Action[0]);
+				}
+				if (target instanceof RuleType) {
+					List<Action> actions = new ArrayList<Action>();
+					actions.add(EDIT_RULE);
+					if (((RuleType) target).getTarget() == null) {
+						actions.add(CREATE_TARGET);
+					}
+					/*
+					actions.add(CLIPBOARD_CUT);
+					actions.add(CLIPBOARD_COPY);
+					actions.add(CLIPBOARD_PASTE);
+					*/
+					if (((RuleType)target).getCondition() == null) {
+						actions.add(CREATE_CONDITION);
+					}
+					actions.add(EDIT_OBLIGATIONS);
+					actions.add(EDIT_ADVICE);
+					actions.add(DELETE_RULE);
+					return (Action[]) actions.toArray(new Action[0]);
+				}
+				if (target instanceof TargetType) {
+					return new Action[] {CREATE_NEWANYOF};
+				}
+				if (target instanceof AnyOfType) {
+					return new Action[] {CREATE_NEWALLOF, DELETE_ANYOF};
+				}
+				if (target instanceof AllOfType) {
+					return new Action[] {CREATE_NEWMATCH, DELETE_ALLOF};
+				}
+				if (target instanceof MatchType) {
+					return new Action[] {EDIT_MATCH, DELETE_MATCH};
+				}
+				if (target instanceof ConditionType) {
+					return new Action[] {EDIT_CONDITION, DELETE_CONDITION};
+				}
+				if (target instanceof VariableDefinitionType) {
+					return new Action[] {EDIT_VARIABLE, DELETE_VARIABLE};
+				}
+				if (target instanceof ObligationExpressionType) {
+					return new Action[] {EDIT_OBLIGATIONS, DELETE_OBLIGATIONS};
+				}
+				if (target instanceof AdviceExpressionType) {
+					return new Action[] {EDIT_ADVICE, DELETE_ADVICE};
+				}
+				return null;
+			}
+			
+			@Override
+			public void handleAction(Action action, Object sender, Object target) {
+				if (action == CLIPBOARD_CUT) {
+					assert target != null;
+					self.clipboardObject = XACMLObjectCopy.deepCopy(target);
+					self.removeObject(target);
+					return;
+				}
+				if (action == CLIPBOARD_COPY) {
+					assert target != null;
+					self.clipboardObject = XACMLObjectCopy.deepCopy(target);
+					return;
+				}
+				if (action == CLIPBOARD_PASTE) {
+					assert target != null;
+					self.clipboardPaste(target, true);
+					return;
+				}
+				if (action == CREATE_POLICYSET) {
+					assert target instanceof PolicySetType;
+					self.editPolicySet(null, (PolicySetType) target);
+					return;
+				}
+				if (action == CREATE_POLICY) {
+					assert target instanceof PolicySetType;
+					self.editPolicy(null, (PolicySetType) target);
+					return;
+				}
+				if (action == CREATE_RULE) {
+					assert target instanceof PolicyType;
+					self.editRule(null, (PolicyType) target);
+					return;
+				}
+				if (action == CREATE_TARGET) {
+					assert target instanceof RuleType || target instanceof PolicyType || target instanceof PolicySetType;
+					TargetType newTarget = new TargetType();
+					self.policyContainer.addItem(newTarget, target);
+					return;
+				}
+				if (action == EDIT_POLICYSET) {
+					assert target instanceof PolicySetType;
+					self.editPolicySet((PolicySetType) target, (PolicySetType) self.policyContainer.getParent(target));
+					return;
+				}
+				if (action == EDIT_POLICY) {
+					assert target instanceof PolicyType;
+					self.editPolicy((PolicyType) target, (PolicySetType) self.policyContainer.getParent(target));
+					return;
+				}
+				if (action == EDIT_RULE) {
+					assert target instanceof RuleType;
+					self.editRule((RuleType) target, (PolicyType) self.policyContainer.getParent(target));
+					return;
+				}				
+				if (action == DELETE_POLICYSET) {
+					assert target instanceof PolicySetType;
+					self.removePolicySet((PolicySetType) target);
+					return;
+				}
+				if (action == DELETE_POLICY) {
+					assert target instanceof PolicyType;
+					self.removePolicy((PolicyType) target);
+					return;
+				}
+				if (action == DELETE_RULE) {
+					assert target instanceof RuleType;
+					self.removeRule((RuleType) target);
+					return;
+				}
+				if (action == CREATE_NEWANYOF) {
+					assert target instanceof TargetType;
+					self.editMatch(null, null, null, (TargetType) target, "Create New Match");
+					return;
+				}
+				if (action == CREATE_NEWALLOF) {
+					assert target instanceof AnyOfType;
+					self.editMatch(null, null, (AnyOfType) target, null, "Create New Match");
+					return;
+				}
+				if (action == CREATE_NEWMATCH) {
+					if (target instanceof AllOfType) {
+						self.editMatch(null, (AllOfType) target, null, null, "Create New Match");
+					} else if (target instanceof TargetType) {
+						self.editMatch(null, null, null, (TargetType) target, "Create New Match");
+					} else {
+						assert false;
+					}
+					return;
+				}
+				if (action == DELETE_ANYOF) {
+					assert target instanceof AnyOfType;
+					self.removeAnyOf((AnyOfType) target, (TargetType) self.policyContainer.getParent(target));
+					return;
+				}
+				if (action == DELETE_ALLOF) {
+					assert target instanceof AllOfType;
+					self.removeAllOf((AllOfType) target, (AnyOfType) self.policyContainer.getParent(target));
+					return;
+				}
+				if (action == DELETE_MATCH) {
+					assert target instanceof MatchType;
+					self.removeMatch((MatchType) target, (AllOfType) self.policyContainer.getParent(target));
+					return;
+				}
+				if (action == EDIT_MATCH) {
+					assert target instanceof MatchType;
+					self.editMatch((MatchType) target, (AllOfType) self.policyContainer.getParent(target), null, null, "Edit Match");
+					return;
+				}
+				if (action == EDIT_OBLIGATIONS) {
+					assert target instanceof RuleType || 
+							target instanceof PolicyType || 
+							target instanceof PolicySetType ||
+							target instanceof ObligationExpressionType;
+					if (target instanceof ObligationExpressionType) {
+						self.editObAdvice(true, self.policyContainer.getParent(target));
+					} else {
+						self.editObAdvice(true, target);
+					}
+					return;
+				}
+				if (action == DELETE_OBLIGATIONS) {
+					assert target instanceof ObligationExpressionType;
+					self.removeObligations((ObligationExpressionType) target);
+					return;
+				}
+				if (action == EDIT_ADVICE) {
+					assert target instanceof RuleType || 
+							target instanceof PolicyType || 
+							target instanceof PolicySetType ||
+							target instanceof AdviceExpressionType;
+					if (target instanceof AdviceExpressionType) {
+						self.editObAdvice(false, self.policyContainer.getParent(target));
+					} else {
+						self.editObAdvice(false, target);
+					}
+					return;
+				}
+				if (action == DELETE_ADVICE) {
+					assert target instanceof AdviceExpressionType;
+					self.removeAdvice((AdviceExpressionType) target);
+					return;
+				}
+				if (action == CREATE_VARIABLE) {
+					assert target instanceof PolicyType;
+					self.editVariable(null, (PolicyType) target);
+					return;
+				}
+				if (action == CREATE_CONDITION) {
+					assert target instanceof RuleType;
+					self.editCondition(null, (RuleType) target);
+					return;
+				}
+				if (action == EDIT_CONDITION) {
+					assert target instanceof ConditionType;
+					self.editCondition((ConditionType) target, (RuleType) self.policyContainer.getParent(target));
+					return;
+				}
+				if (action == DELETE_CONDITION) {
+					assert target instanceof ConditionType;
+					self.removeCondition((ConditionType) target);
+					return;
+				}
+				if (action == EDIT_EXPRESSIONS) {
+					return;
+				}
+				if (action == DELETE_VARIABLE) {
+					assert target instanceof VariableDefinitionType;
+					self.removeVariable((VariableDefinitionType) target);
+					return;
+				}
+				if (action == EDIT_VARIABLE) {
+					assert target instanceof VariableDefinitionType;
+					self.editVariable((VariableDefinitionType) target, (PolicyType) self.policyContainer.getParent(target));
+					return;
+				}
+			}
+		});		
+	}
+	
+	protected void resetComponents() {
+		if (this.isReadOnly()) {
+			this.checkBoxAutoSave.setEnabled(false);
+			this.buttonSave.setEnabled(false);
+			this.tree.setDragMode(TableDragMode.NONE);
+			this.tree.removeAllActionHandlers();
+			this.tree.setReadOnly(true);
+		} else {
+			this.checkBoxAutoSave.setEnabled(true);
+			this.buttonSave.setEnabled(this.isModified);
+			this.tree.setReadOnly(false);
+			this.tree.setDragMode(TableDragMode.ROW);
+			this.installTreeActionHandler();
+		}
+	}
+		
+	public void	setupCaption() {
+		String caption = this.file.getName();
+		if (this.isModified) {
+			caption = caption + " *";
+		}
+		if (this.isReadOnly()) {
+			caption = caption + " (Read-Only)";
+		}
+		if (this.tab != null) {
+			this.tab.setCaption(caption);
+		}
+	}
+	
+	protected void editPolicySet(final PolicySetType policy, final PolicySetType parent) {
+		logger.info("editPolicySet: " + policy + " parent " + parent);
+		//
+		// Create a copy
+		//
+		final PolicySetType newPolicySet = (policy == null ? new PolicySetType() : XACMLObjectCopy.copy(policy));
+		//
+		// Create window
+		//
+		final PolicySetEditorWindow window = new PolicySetEditorWindow(newPolicySet);
+		window.setCaption(policy == null ? "Create New Policy Set" : "Edit Policy Set");
+		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) {
+					if (logger.isDebugEnabled()) {
+						logger.debug("user did NOT save");
+					}
+					return;
+				}
+				//
+				// Was it a new Policy Set?
+				//
+				if (policy == null) {
+					logger.info("adding new policy set " + newPolicySet.getPolicySetId());
+					//
+					// Yes - new add it in
+					//
+					if (newPolicySet.getTarget() == null) {
+						newPolicySet.setTarget(new TargetType());
+					}
+					if (self.policyContainer.addItem(newPolicySet, parent) == null) {
+						logger.error("Failed to add new policy set");
+					} else {
+						self.tree.setCollapsed(parent, false);
+						self.tree.setCollapsed(newPolicySet, false);
+						self.tree.select(newPolicySet);
+					}
+				} else {
+					logger.info("updating new policy set " + newPolicySet.getPolicySetId());
+					//
+					// No - copy everything
+					//
+					policy.setDescription(newPolicySet.getDescription());
+					policy.setVersion(newPolicySet.getVersion());
+					policy.setPolicyCombiningAlgId(newPolicySet.getPolicyCombiningAlgId());
+					//
+					// Update
+					//
+					self.policyContainer.updateItem(policy);
+				}
+			}			
+		});
+		window.center();
+		UI.getCurrent().addWindow(window);
+	}
+	
+	protected void editPolicy(final PolicyType policy, final PolicySetType parent) {
+		//
+		// Create a copy
+		//
+		final PolicyType newPolicy = (policy == null ? new PolicyType() : XACMLObjectCopy.copy(policy));
+		//
+		// Create window
+		//
+		final PolicyEditorWindow window = new PolicyEditorWindow(newPolicy);
+		window.setCaption(policy == null ? "Create New Policy" : "Edit Policy");
+		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;
+				}
+				//
+				// Was it a new Policy?
+				//
+				if (policy == null) {
+					//
+					// Yes - new add it in
+					//
+					if (newPolicy.getTarget() == null) {
+						newPolicy.setTarget(new TargetType());
+					}
+					if (self.policyContainer.addItem(newPolicy, parent) == null) {
+						logger.error("Failed to add policy");
+					} else {
+						self.tree.setCollapsed(parent, false);
+						self.tree.setCollapsed(newPolicy, false);
+						self.tree.select(newPolicy);
+					}
+				} else {
+					//
+					// No - copy everything
+					//
+					policy.setDescription(newPolicy.getDescription());
+					policy.setVersion(newPolicy.getVersion());
+					policy.setRuleCombiningAlgId(newPolicy.getRuleCombiningAlgId());
+					//
+					// Update
+					//
+					self.policyContainer.updateItem(policy);
+				}
+			}			
+		});
+		window.center();
+		UI.getCurrent().addWindow(window);
+	}
+	
+	protected void editRule(final RuleType rule, final PolicyType parent) {
+		//
+		// Create a copy
+		//
+		final RuleType newRule = (rule == null ? new RuleType() : XACMLObjectCopy.copy(rule));
+		//
+		// Create window
+		//
+		final RuleEditorWindow window = new RuleEditorWindow(newRule);
+		window.setCaption(rule == null ? "Create New Rule" : "Edit Rule");
+		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;
+				}
+				//
+				// Was this a new rule?
+				//
+				if (rule == null) {
+					//
+					// Yes a new rule
+					//
+					if (newRule.getTarget() == null) {
+						newRule.setTarget(new TargetType());
+					}
+					if (self.policyContainer.addItem(newRule, parent) == null) {
+						logger.error("Failed to add new rule");
+					} else {
+						self.tree.setCollapsed(parent, false);
+						self.tree.setCollapsed(newRule, false);
+						self.tree.select(newRule);
+					}
+				} else {
+					//
+					// No - editing existing rule. Copy everything
+					//
+					rule.setEffect(newRule.getEffect());
+					rule.setDescription(newRule.getDescription());
+					self.policyContainer.updateItem(rule);
+				}
+			}
+		});
+		window.center();
+		UI.getCurrent().addWindow(window);
+	}
+
+	protected void editCondition(final ConditionType condition, final RuleType rule) {
+		//
+		// Make a copy of it first, in case the user manipulates it
+		// and then decides to NOT save it
+		//
+		final ConditionType copyCondition = (condition == null ? new ConditionType() : XACMLObjectCopy.copy(condition));
+		//
+		// Create the window
+		//
+		final ExpressionBuilderComponent expression = new ExpressionBuilderComponent(copyCondition, 
+											(copyCondition.getExpression() != null ? copyCondition.getExpression().getValue() : null), 
+											null,
+											self.policyContainer.getVariables());
+		if (condition == null) {
+			expression.setCaption("Create An Expression For The Condition");
+		} else {
+			expression.setCaption("Edit The Condition Expression");
+		}
+		expression.setModal(true);
+		//
+		// Add the close listener
+		//
+		expression.addCloseListener(new CloseListener() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void windowClose(CloseEvent e) {
+				//
+				// Did the user hit save?
+				//
+				if (expression.isSaved() == false) {
+					return;
+				}
+				//
+				// Were we creating something new?
+				//
+				if (condition == null) {
+					//
+					// Yes add the new one into the container
+					//
+					if (self.policyContainer.addItem(copyCondition, rule) == null) {
+						logger.error("Failed to add condition");
+					} else {
+						self.tree.setCollapsed(rule, false);
+						self.tree.setCollapsed(copyCondition, false);
+						self.tree.select(copyCondition);
+					}
+				} else {
+					//
+					// We were editing an existing condition, so copy
+					// over the new edited expression.
+					//
+					condition.setExpression(copyCondition.getExpression());
+					//
+					// Update the container
+					//
+					self.policyContainer.updateItem(condition);
+				}
+			}			
+		});
+		expression.center();
+		UI.getCurrent().addWindow(expression);
+	}
+
+	protected void editVariable(final VariableDefinitionType variable, final PolicyType parent) {
+		//
+		// Make a copy of it first, in case the user manipulates it
+		// and then decides to NOT save it
+		//
+		final VariableDefinitionType copyVariable = (variable == null ? new VariableDefinitionType(): XACMLObjectCopy.copy(variable));
+		//
+		// Have the user create or edit the Variables ID
+		//
+		final VariableDefinitionEditorWindow editor = new VariableDefinitionEditorWindow(copyVariable);
+		if (variable == null) {
+			editor.setCaption("Create Variable");			
+		} else {
+			editor.setCaption("Edit Variable" + (copyVariable.getVariableId() == null ? "" : copyVariable.getVariableId()));
+		}
+		editor.setModal(true);
+		editor.addCloseListener(new CloseListener() {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void windowClose(CloseEvent e) {
+				//
+				// Did the user click save button?
+				//
+				if (editor.isSaved() == false) {
+					return;
+				}
+				//
+				// Create the window
+				//
+				final ExpressionBuilderComponent expression = new ExpressionBuilderComponent(copyVariable, 
+													(copyVariable.getExpression() != null ? copyVariable.getExpression().getValue() : null), 
+													null, 
+													self.policyContainer.getVariables());
+				expression.setCaption("Edit The Variable \"" + copyVariable.getVariableId() + "\" Expression");
+				//
+				// Add the close listener
+				//
+				expression.addCloseListener(new CloseListener() {
+					private static final long serialVersionUID = 1L;
+		
+					@Override
+					public void windowClose(CloseEvent e) {
+						//
+						// Did the user click save button?
+						//
+						if (expression.isSaved() == false) {
+							return;
+						}
+						//
+						// Was it a new variable or were we editing an existing one?
+						//
+						if (variable == null) {
+							//
+							// New one, add it to the container
+							//
+							if (self.policyContainer.addItem(copyVariable, parent) == null) {
+								logger.error("Failed to add variable");
+							} else {
+								self.tree.setCollapsed(parent, false);
+								self.tree.setCollapsed(copyVariable, false);
+								self.tree.select(copyVariable);
+							}
+						} else {
+							//
+							// We were editing one, copy it back over.
+							//
+							variable.setVariableId(copyVariable.getVariableId());
+							variable.setExpression(copyVariable.getExpression());
+							//
+							// Update the container
+							//
+							self.policyContainer.updateItem(variable);
+						}
+					}
+				});
+				expression.center();
+				UI.getCurrent().addWindow(expression);
+			}
+		});
+		editor.center();
+		UI.getCurrent().addWindow(editor);
+	}
+
+	protected void editMatch(final MatchType match, final AllOfType allOf, final AnyOfType anyOf, final TargetType target, final String caption) {
+		//
+		// Create an empty match or copy the one we are going to edit.
+		//
+		final MatchType newMatch = (match == null ? new MatchType() : XACMLObjectCopy.copy(match));
+		//
+		// Have user select an attribute
+		//
+		final AttributeSelectionWindow selection = new AttributeSelectionWindow(null, 
+									(newMatch.getAttributeDesignator() != null ? newMatch.getAttributeDesignator() : newMatch.getAttributeSelector()));
+		selection.setCaption("Select Attribute To Match Against");
+		selection.setModal(true);
+		selection.addCloseListener(new CloseListener() {
+			private static final long serialVersionUID = 1L;
+			
+			@Override
+			public void windowClose(CloseEvent event) {
+				//
+				// Did the user save anything?
+				//
+				if (selection.isSaved() == false) {
+					return;
+				}
+				//
+				// Save the selected attribute
+				//
+				final Attribute attribute = selection.getAttribute();
+				if (attribute.isDesignator()) {
+					newMatch.setAttributeDesignator(JPAUtils.createDesignator(attribute));
+				} else {
+					newMatch.setAttributeSelector(JPAUtils.createSelector(attribute));
+				}
+				//
+				// Yes - now match it up to a function
+				//
+				final MatchEditorWindow editor = new MatchEditorWindow(newMatch, attribute.getDatatypeBean());
+				editor.setCaption(caption);
+				editor.setModal(true);
+				editor.addCloseListener(new CloseListener() {
+					private static final long serialVersionUID = 1L;
+					
+					@Override
+					public void windowClose(CloseEvent event) {
+						//
+						// Did the user hit save?
+						//
+						if (editor.isSaved() == false) {
+							return;
+						}
+						//
+						// Yes - now we need the value to check the attribute against
+						//
+						final AttributeValueType copyAttributeValue = (newMatch.getAttributeValue() == null ? new AttributeValueType() : newMatch.getAttributeValue());
+//						String currentValue = null;
+//						if (newMatch.getAttributeValue() != null) {
+//							currentValue = XACMLObjectCopy.getContent(newMatch.getAttributeValue().getContent());
+//						}
+						final AttributeValueEditorWindow value = new AttributeValueEditorWindow(copyAttributeValue, attribute.getDatatypeBean());
+						value.setCaption("Set the value the attribute should match against.");
+						value.setModal(true);
+						value.addCloseListener(new CloseListener() {
+							private static final long serialVersionUID = 1L;
+							
+							@Override
+							public void windowClose(CloseEvent event) {
+								//
+								// Did the user save?
+								//
+								if (value.isSaved() == false) {
+									return;
+								}
+								//
+								// Yes - copy the value into the match
+								//
+								AttributeValueType val = new AttributeValueType();
+								val.getContent().add(value.getValue());
+								val.setDataType(value.getDatatype().getXacmlId());
+								newMatch.setAttributeValue(val);
+								//
+								// Was this a new match or were we editing an
+								// existing match?
+								//
+								if (match != null) {
+									//
+									// Editing - now we can save it
+									//
+									match.setAttributeDesignator(newMatch.getAttributeDesignator());
+									match.setAttributeSelector(newMatch.getAttributeSelector());
+									match.setAttributeValue(newMatch.getAttributeValue());
+									match.setMatchId(newMatch.getMatchId());
+									//
+									// Update the container
+									//
+									self.policyContainer.updateItem(match);
+								} else {
+									//
+									// Do we have a parent(s)?
+									//
+									AllOfType allOfParent = allOf;
+									AnyOfType anyOfParent = anyOf;
+									if (allOfParent == null) {
+										//
+										// No direct AllOfParent
+										//
+										if (anyOfParent == null) {
+											//
+											// No AnyOfParent
+											//
+											if (target == null) {
+												logger.error("We should NOT get this");
+												return;
+											}
+											anyOfParent = new AnyOfType();
+											if (self.policyContainer.addItem(anyOfParent, target) == null) {
+												logger.error("Failed to add anyOf parent");
+												assert false;
+											}
+											self.tree.setCollapsed(anyOfParent, false);
+										}
+										allOfParent = new AllOfType();
+										if (self.policyContainer.addItem(allOfParent, anyOfParent) == null) {
+											logger.error("Failed to add allOf parent");
+											assert false;
+										}
+										self.tree.setCollapsed(allOfParent, false);
+									}
+									//
+									// Add the MatchType into the Tree
+									//
+									if (self.policyContainer.addItem(newMatch, allOfParent) == null) {
+										logger.error("Failed to add match");
+										assert false;
+									}
+									self.tree.select(newMatch);
+								}
+							}								
+						});
+						value.center();
+						UI.getCurrent().addWindow(value);
+					}
+				});
+				editor.center();
+				UI.getCurrent().addWindow(editor);
+			}
+		});
+		selection.center();
+		UI.getCurrent().addWindow(selection);
+	}
+	
+	protected void deleteRoot(Object root) {
+		//
+		// TODO - prompt user for new root object
+		//
+		
+	}
+	
+	protected void editObAdvice(boolean isObligation, final Object target) {
+		//
+		// Get the object
+		//
+		String caption;
+		Object expressionsObject = null;
+		if (target instanceof RuleType) {
+			if (isObligation) {
+				expressionsObject = ((RuleType) target).getObligationExpressions();
+				if (expressionsObject == null) {
+					caption = "Create New Obligation for Rule";
+				} else {
+					caption = "Edit Obligations for Rule"; 
+				}
+			} else {
+				expressionsObject = ((RuleType) target).getAdviceExpressions();
+				if (expressionsObject == null) {
+					caption = "Create New Advice for Rule";
+				} else {
+					caption = "Edit Advice for Rule"; 
+				}
+			}
+		} else if (target instanceof PolicyType) {
+			if (isObligation) {
+				expressionsObject = ((PolicyType) target).getObligationExpressions();
+				if (expressionsObject == null) {
+					caption = "Create New Obligation for Policy";
+				} else {
+					caption = "Edit Obligations for Policy"; 
+				}
+			} else {
+				expressionsObject = ((PolicyType) target).getAdviceExpressions();
+				if (expressionsObject == null) {
+					caption = "Create New Advice for Policy";
+				} else {
+					caption = "Edit Advice for Policy"; 
+				}
+			}
+		} else if (target instanceof PolicySetType) {
+			if (isObligation) {
+				expressionsObject = ((PolicySetType) target).getObligationExpressions();
+				if (expressionsObject == null) {
+					caption = "Create New Obligation for Policy Set";
+				} else {
+					caption = "Edit Obligation for Policy Set"; 
+				}
+			} else {
+				expressionsObject = ((PolicySetType) target).getAdviceExpressions();
+				if (expressionsObject == null) {
+					caption = "Create New Advice for Policy Set";
+				} else {
+					caption = "Edit Advice for Policy Set"; 
+				}
+			}
+		} else {
+			throw new IllegalArgumentException("Expected a rule/policy/policyset.");
+		}
+		//
+		// Make a copy
+		//
+		final Object originalExpressions = expressionsObject;
+		final Object copyExpression = (originalExpressions == null 
+										? (isObligation ? new ObligationExpressionsType() : new AdviceExpressionsType())
+										: originalExpressions instanceof ObligationExpressionsType 
+												? XACMLObjectCopy.copy((ObligationExpressionsType) originalExpressions)
+												: XACMLObjectCopy.copy((AdviceExpressionsType) originalExpressions))
+										;
+		//
+		// Invoke the editor window
+		//
+		final ObligationAdviceEditorWindow window = new ObligationAdviceEditorWindow(copyExpression, this.policyContainer.getVariables());
+		window.setCaption(caption);
+		window.setModal(true);
+		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;
+				}
+				//
+				// It was saved - is this a new object?
+				//
+				if (originalExpressions == null) {
+					//
+					// New object
+					//
+					if (self.policyContainer.addItem(copyExpression, target) == null) {
+						logger.error("Failed to add expression");
+						assert false;
+					}
+				} else {
+					//
+					// Editing an existing object.
+					//
+					if (originalExpressions instanceof ObligationExpressionsType) {
+						//
+						// Remove old obligations
+						//
+						while (((ObligationExpressionsType) originalExpressions).getObligationExpression().isEmpty() == false) {
+//						for (ObligationExpressionType old : ((ObligationExpressionsType) originalExpressions).getObligationExpression()) {
+							ObligationExpressionType old  = ((ObligationExpressionsType) originalExpressions).getObligationExpression().get(0);
+							self.policyContainer.removeItem(old);
+						}
+						//
+						// Copy new ones in
+						//
+						for (ObligationExpressionType newObligation : ((ObligationExpressionsType) copyExpression).getObligationExpression()) {
+							self.policyContainer.addItem(newObligation, (ObligationExpressionsType) originalExpressions);
+						}
+					} else if (originalExpressions instanceof AdviceExpressionsType) {
+						((AdviceExpressionsType) originalExpressions).getAdviceExpression().clear();
+						((AdviceExpressionsType) originalExpressions).getAdviceExpression().addAll(((AdviceExpressionsType) copyExpression).getAdviceExpression());
+					}
+				}
+			}
+		});
+		window.center();
+		UI.getCurrent().addWindow(window);
+	}
+	
+	protected void removeMatch(MatchType match, AllOfType parent) {
+		assert match != null && parent != null;
+		if (self.policyContainer.removeItem(match) == false) {
+			logger.error("Failed to remove match");
+			assert false;
+		}
+		//
+		// Check for empty AllOf's
+		//
+		if (parent.getMatch().isEmpty()) {
+			this.removeAllOf(parent, (AnyOfType) this.policyContainer.getParent(parent));
+		}
+	}
+
+	protected void removeAllOf(AllOfType allOf, AnyOfType parent) {
+		assert allOf != null && parent != null;
+		if (self.policyContainer.removeItem(allOf) == false) {
+			logger.error("Failed to remove AllOf");
+			assert false;
+		}
+		//
+		// Check for empty AnyOf's
+		//
+		if (parent.getAllOf().isEmpty()) {
+			this.removeAnyOf(parent, (TargetType) this.policyContainer.getParent(parent));
+		}
+	}
+
+	protected void removeAnyOf(AnyOfType anyOf, TargetType parent) {
+		assert anyOf != null && parent != null;
+		if (self.policyContainer.removeItem(anyOf) == false) {
+			logger.error("Failed to remove anyOf");
+			assert false;
+		}
+	}
+
+	protected boolean clipboardPaste(final Object target, boolean performPaste) {
+		if (this.clipboardObject == null) {
+			if (logger.isDebugEnabled()) {
+				logger.debug("nothing in clipboard.");
+			}
+			return false;
+		}
+		boolean doPaste = false;
+		if (this.clipboardObject instanceof PolicySetType && target instanceof PolicySetType) {
+			doPaste = true;
+		}
+		if (this.clipboardObject instanceof PolicyType && target instanceof PolicySetType) {
+			doPaste = true;
+		}
+		if (this.clipboardObject instanceof RuleType && target instanceof PolicyType) {
+			doPaste = true;
+		}
+		if (doPaste == false) {
+			//
+			// Pasting clipboard object onto target not
+			// possible.
+			//
+			return false;
+		}
+		if (performPaste == false) {
+			//
+			// They did not ask to do the actual paste,
+			// but the called wanted to know if it was
+			// possible.
+			//
+			return true;
+		}
+		//
+		// Do the actual paste
+		//
+		Item item = this.policyContainer.addItem(XACMLObjectCopy.deepCopy(this.clipboardObject), target);
+		assert item != null;
+		this.tree.select(this.clipboardObject);
+		
+		return true;
+	}
+	
+	@AutoGenerated
+	private VerticalLayout buildMainLayout() {
+		// common part: create layout
+		mainLayout = new VerticalLayout();
+		mainLayout.setImmediate(false);
+		mainLayout.setWidth("-1px");
+		mainLayout.setHeight("100.0%");
+		mainLayout.setMargin(false);
+		mainLayout.setSpacing(true);
+		
+		// top-level component properties
+		setWidth("-1px");
+		setHeight("100.0%");
+		
+		// horizontalLayoutToolbar
+		horizontalLayoutToolbar = buildHorizontalLayoutToolbar();
+		mainLayout.addComponent(horizontalLayoutToolbar);
+		mainLayout.setExpandRatio(horizontalLayoutToolbar, 1.0f);
+		
+		// tree
+		tree = new TreeTable();
+		tree.setImmediate(true);
+		tree.setWidth("100.0%");
+		tree.setHeight("100.0%");
+		mainLayout.addComponent(tree);
+		mainLayout.setExpandRatio(tree, 1.0f);
+		
+		return mainLayout;
+	}
+
+	@AutoGenerated
+	private HorizontalLayout buildHorizontalLayoutToolbar() {
+		// common part: create layout
+		horizontalLayoutToolbar = new HorizontalLayout();
+		horizontalLayoutToolbar.setImmediate(false);
+		horizontalLayoutToolbar.setWidth("-1px");
+		horizontalLayoutToolbar.setHeight("-1px");
+		horizontalLayoutToolbar.setMargin(true);
+		horizontalLayoutToolbar.setSpacing(true);
+		
+		// checkBoxReadOnly
+		checkBoxReadOnly = new CheckBox();
+		checkBoxReadOnly.setCaption("Read Only");
+		checkBoxReadOnly.setImmediate(false);
+		checkBoxReadOnly
+				.setDescription("Check this to turn-off policy editing.");
+		checkBoxReadOnly.setWidth("-1px");
+		checkBoxReadOnly.setHeight("-1px");
+		horizontalLayoutToolbar.addComponent(checkBoxReadOnly);
+		
+		// checkBoxAutoSave
+		checkBoxAutoSave = new CheckBox();
+		checkBoxAutoSave.setCaption("Auto Save");
+		checkBoxAutoSave.setImmediate(false);
+		checkBoxAutoSave
+				.setDescription("Check this to turn-on automatic saving of policy when a change occurs.");
+		checkBoxAutoSave.setWidth("-1px");
+		checkBoxAutoSave.setHeight("-1px");
+		horizontalLayoutToolbar.addComponent(checkBoxAutoSave);
+		
+		// buttonSave
+		buttonSave = new Button();
+		buttonSave.setCaption("Save");
+		buttonSave.setImmediate(true);
+		buttonSave.setDescription("Click to save the policy.");
+		buttonSave.setWidth("-1px");
+		buttonSave.setHeight("-1px");
+		horizontalLayoutToolbar.addComponent(buttonSave);
+		
+		// buttonViewXML
+		buttonViewXML = new Button();
+		buttonViewXML.setCaption("View XML");
+		buttonViewXML.setImmediate(true);
+		buttonViewXML.setWidth("-1px");
+		buttonViewXML.setHeight("-1px");
+		horizontalLayoutToolbar.addComponent(buttonViewXML);
+		
+		// buttonExport
+		buttonExport = new Button();
+		buttonExport.setCaption("Export Policy");
+		buttonExport.setImmediate(false);
+		buttonExport.setWidth("-1px");
+		buttonExport.setHeight("-1px");
+		horizontalLayoutToolbar.addComponent(buttonExport);
+		
+		return horizontalLayoutToolbar;
+	}
+}