org.apache.openaz.xacml.admin.components.PolicyWorkspace.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.openaz.xacml.admin.components.PolicyWorkspace.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.components;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection;
import java.util.Iterator;

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 org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.PushResult;
import org.vaadin.dialogs.ConfirmDialog;
import org.vaadin.dialogs.ConfirmDialog.ContentMode;

import org.apache.openaz.xacml.admin.XacmlAdminAuthorization;
import org.apache.openaz.xacml.admin.XacmlAdminUI;
import org.apache.openaz.xacml.admin.model.GitRepositoryContainer;
import org.apache.openaz.xacml.admin.util.AdminNotification;
import org.apache.openaz.xacml.admin.util.OnDemandFileDownloader;
import org.apache.openaz.xacml.admin.util.OnDemandFileDownloader.OnDemandStreamResource;
import org.apache.openaz.xacml.admin.util.XACMLPolicyImporter;
import org.apache.openaz.xacml.admin.view.windows.GitPushWindow;
import org.apache.openaz.xacml.admin.view.windows.GitSynchronizeWindow;
import org.apache.openaz.xacml.admin.view.windows.PolicyNameEditorWindow;
import org.apache.openaz.xacml.admin.view.windows.PolicyUploadWindow;
import org.apache.openaz.xacml.admin.view.windows.RenamePolicyFileWindow;
import org.apache.openaz.xacml.admin.view.windows.SubDomainEditorWindow;
import org.apache.openaz.xacml.std.pap.StdPDPPolicy;
import org.apache.openaz.xacml.util.XACMLPolicyScanner;
import org.apache.openaz.xacml.util.XACMLPolicyScanner.CallbackResult;
import org.apache.openaz.xacml.util.XACMLPolicyWriter;
import com.vaadin.annotations.AutoGenerated;
import com.vaadin.data.Item;
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.event.Transferable;
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.ui.AbstractSelect.AbstractSelectTargetDetails;
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.Component;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.Notification;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TabSheet.CloseHandler;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.Table.TableDragMode;
import com.vaadin.ui.Table.TableTransferable;
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;

/**
 * The class represents Policy Editor in Policy Authoring Tool
 */
public class PolicyWorkspace extends CustomComponent implements DropHandler, OnDemandStreamResource {
    /*- VaadinEditorProperties={"grid":"RegularGrid,20","showGrid":true,"snapToGrid":true,"snapToObject":true,"movingGuides":false,"snappingDistance":10} */

    @AutoGenerated
    private VerticalLayout mainLayout;

    @AutoGenerated
    private HorizontalSplitPanel horizontalSplitPanel;

    @AutoGenerated
    private VerticalLayout verticalLayoutRightPanel;

    @AutoGenerated
    private TabSheet tabSheet;

    @AutoGenerated
    private HorizontalLayout horizontalLayoutRightToolbar;

    @AutoGenerated
    private Button buttonRight;

    @AutoGenerated
    private VerticalLayout verticalLayoutLeftPanel;

    @AutoGenerated
    private TreeTable treeWorkspace;

    @AutoGenerated
    private HorizontalLayout horizontalLayoutLeftToolbar;

    @AutoGenerated
    private Button buttonLeft;

    @AutoGenerated
    private HorizontalLayout horizontalLayoutLeftToolbarLeft;

    @AutoGenerated
    private Button buttonExport;

    @AutoGenerated
    private Button buttonSynchronize;

    private static final long serialVersionUID = 1L;
    private static final Log logger = LogFactory.getLog(PolicyWorkspace.class);
    private final PolicyWorkspace self = this;
    private final OnDemandFileDownloader downloader = new OnDemandFileDownloader(this);

    private GitRepositoryContainer treeContainer;

    private static final Action EXPORT_REPOSITORY = new Action("Export Repository");
    private static final Action SYNCHRONIZE_REPOSITORY = new Action("Synchronize");
    private static final Action PUSH_CHANGES = new Action("Push Changes");
    private static final Action CREATE_SUBDOMAIN = new Action("Create Sub Domain");
    private static final Action RENAME_SUBDOMAIN = new Action("Rename Sub Domain");
    private static final Action CREATE_NEWPOLICY = new Action("Create New Policy");
    private static final Action RENAME_POLICY = new Action("Rename Policy");
    private static final Action IMPORT_POLICY = new Action("Import Policy");
    private static final Action DELETE_SUBDOMAIN = new Action("Delete Sub Domain");
    private static final Action CLONE_POLICY = new Action("Clone Policy");
    private static final Action VIEW_POLICY = new Action("View Policy");
    private static final Action EDIT_POLICY = new Action("Edit Policy");
    private static final Action EXPORT_POLICY = new Action("Export Policy");
    private static final Action DELETE_POLICY = new Action("Delete Policy");

    public static final String VIEWNAME = PolicyWorkspace.class.getCanonicalName();

    /**
     * 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 PolicyWorkspace() {
        buildMainLayout();
        setCompositionRoot(mainLayout);
        //
        // Initialize GUI
        //
        this.initializeTree();
        this.initializeButtons();
    }

    protected void initializeButtons() {
        buttonLeft.addClickListener(new ClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void buttonClick(ClickEvent event) {
                if (horizontalSplitPanel.getSplitPosition() == 100.0)
                    horizontalSplitPanel.setSplitPosition(36, Unit.PERCENTAGE);
                else
                    horizontalSplitPanel.setSplitPosition(0);
            }
        });
        buttonRight.addClickListener(new ClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void buttonClick(ClickEvent event) {
                if (horizontalSplitPanel.getSplitPosition() == 0.0)
                    horizontalSplitPanel.setSplitPosition(36, Unit.PERCENTAGE);
                else
                    horizontalSplitPanel.setSplitPosition(100, Unit.PERCENTAGE);
            }
        });
        //
        // Check user write-access
        //
        if (((XacmlAdminUI) UI.getCurrent()).isAuthorized(XacmlAdminAuthorization.AdminAction.ACTION_WRITE,
                XacmlAdminAuthorization.AdminResource.RESOURCE_POLICY_WORKSPACE)) {
            this.buttonSynchronize.addClickListener(new ClickListener() {
                private static final long serialVersionUID = 1L;

                @Override
                public void buttonClick(ClickEvent event) {
                    self.synchronizeRepository();
                }
            });
        } else {
            logger.info("user not authorized to write, removing synchronize button.");
            this.buttonSynchronize.setVisible(false);
        }
        //
        // The export button is attached to dynamic downloader
        //
        downloader.extend(this.buttonExport);
    }

    protected void initializeTree() {
        //
        // This is where the user's Git repository is located
        //
        final Path gitPath = ((XacmlAdminUI) UI.getCurrent()).getUserGitPath();
        //
        // Create our Git file system container
        //
        this.treeContainer = new GitRepositoryContainer(gitPath, gitPath.toFile());
        //
        // Create our own filter to filter out File extensions and
        // also the Git directory.
        //
        this.treeContainer.setFilter(new FilenameFilter() {

            @Override
            public boolean accept(File dir, String name) {
                //
                // We don't want any of the hidden files
                //
                if (name.startsWith(".git") || name.equals(".DS_Store")) {
                    return false;
                }
                //
                // We definitely want xml files
                //
                if (name.endsWith(".xml")) {
                    return true;
                }
                //
                // We should test if its a directory, we want those
                // included.
                //
                Path path = Paths.get(dir.getAbsolutePath(), name);
                if (Files.isDirectory(path)) {
                    return true;
                }
                logger.warn("Filtering out: " + path.toString());
                return false;
            }

        });
        //
        // Set TreeTables datasource as our git container
        //
        this.treeWorkspace.setContainerDataSource(this.treeContainer);
        //
        // Setup other properties etc.
        //
        this.treeWorkspace.setItemIconPropertyId("Icon");
        this.treeWorkspace.setVisibleColumns(new Object[] { "Name", "Version", "Size", "Last Modified", "Status" });
        this.treeWorkspace.setSizeFull();
        this.treeWorkspace.setSelectable(true);
        this.treeWorkspace.setEditable(false);
        //
        // Expand the first couple of directories
        //
        for (Object id : this.treeWorkspace.getItemIds()) {
            this.treeWorkspace.setCollapsed(id, false);
            for (Object child : this.treeWorkspace.getChildren(id)) {
                this.treeWorkspace.setCollapsed(child, false);
            }
        }
        //
        // Respond to table selections
        //
        /*
        this.treeWorkspace.addValueChangeListener(new ValueChangeListener() {
           private static final long serialVersionUID = 1L;
            
           @Override
           public void valueChange(ValueChangeEvent event) {
        File selection = (File) self.treeWorkspace.getValue();
        if (selection != null) {
           self.buttonImport.setEnabled(selection.isDirectory());
           self.buttonExport.setEnabled(selection.isFile());
        } else {
               
        }
           }
               
        });
        */
        this.treeWorkspace.addItemClickListener(new ItemClickListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void itemClick(ItemClickEvent event) {
                if (event.isDoubleClick() && event.getItemId() instanceof File
                        && ((File) event.getItemId()).isFile()) {
                    self.openPolicyTab((File) event.getItemId(), true);
                }
            }
        });
        //
        // Setup our action handlers
        //
        this.treeWorkspace.addActionHandler(new Handler() {
            private static final long serialVersionUID = 1L;

            @Override
            public Action[] getActions(Object target, Object sender) {
                if (target == null) {
                    //
                    // Nothing is selected, they right-clicked empty space
                    //
                    return new Action[] { SYNCHRONIZE_REPOSITORY, EXPORT_REPOSITORY, CREATE_SUBDOMAIN };
                }
                if (!(target instanceof File)) {
                    return null;
                }
                if (((File) target).isDirectory()) {
                    //
                    // Selected a directory
                    //
                    return new Action[] { CREATE_SUBDOMAIN, RENAME_SUBDOMAIN, DELETE_SUBDOMAIN, CREATE_NEWPOLICY,
                            IMPORT_POLICY, PUSH_CHANGES };
                }
                if (((File) target).isFile()) {
                    //
                    // Selected a policy file
                    //
                    return new Action[] { VIEW_POLICY, EDIT_POLICY, CLONE_POLICY, EXPORT_POLICY, RENAME_POLICY,
                            DELETE_POLICY, PUSH_CHANGES };
                }
                return null;
            }

            @Override
            public void handleAction(Action action, Object sender, Object target) {
                if (action == SYNCHRONIZE_REPOSITORY) {
                    self.synchronizeRepository();
                    return;
                }
                if (action == EXPORT_REPOSITORY) {
                    self.exportRepository();
                    return;
                }
                if (action == PUSH_CHANGES) {
                    self.pushChanges((File) target);
                    return;
                }
                if (action == CREATE_SUBDOMAIN) {
                    self.editSubDomain((File) target, null);
                    return;
                }
                if (action == RENAME_SUBDOMAIN) {
                    self.editSubDomain((File) self.treeWorkspace.getParent(target), ((File) target).getName());
                    return;
                }
                if (action == CREATE_NEWPOLICY) {
                    self.createPolicy((File) target);
                    return;
                }
                if (action == RENAME_POLICY) {
                    self.renamePolicy((File) target);
                    return;

                }
                if (action == IMPORT_POLICY) {
                    self.importPolicy((File) target);
                    return;
                }
                if (action == DELETE_SUBDOMAIN) {
                    self.deleteSubDomain((File) target);
                    return;
                }
                if (action == CLONE_POLICY) {
                    self.clonePolicy((File) target);
                    return;
                }
                if (action == VIEW_POLICY) {
                    self.openPolicyTab((File) target, true);
                    return;
                }
                if (action == EDIT_POLICY) {
                    self.openPolicyTab((File) target, false);
                    return;
                }
                if (action == EXPORT_POLICY) {
                    return;

                }
                if (action == DELETE_POLICY) {
                    self.deletePolicy((File) target);
                    return;
                }
            }
        });
        //
        // Set the drop handler
        //
        this.treeWorkspace.setDragMode(TableDragMode.ROW);
        this.treeWorkspace.setDropHandler(this);
        //
        // Detect when a tab closes and remove it from the
        // tab sheet.
        //
        this.tabSheet.setCloseHandler(new CloseHandler() {
            private static final long serialVersionUID = 1L;

            @Override
            public void onTabClose(TabSheet tabsheet, Component tabContent) {
                logger.info("tabsheet closing: " + tabsheet.getCaption());
                tabsheet.removeTab(tabsheet.getTab(tabContent));
            }

        });
    }

    protected void editSubDomain(final File parent, final String subdomain) {
        final SubDomainEditorWindow editor = new SubDomainEditorWindow(null);
        editor.setCaption((subdomain == null ? "Create New SubDomain" : "Edit SubDomain"));
        editor.setCloseShortcut(KeyCode.ESCAPE);
        editor.setModal(true);
        editor.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent event) {
                //
                // Did the user save it
                //
                if (editor.isSaved() == false) {
                    return;
                }
                String newSubDomain = editor.getSubDomain();
                if (newSubDomain == null) {
                    logger.warn("Shouldn't have a null subdomain if the user clicked save button");
                    return;
                }
                //
                // New subdomain?
                //
                if (subdomain == null) {
                    //
                    // Create new one
                    //
                    Path createDir;
                    if (parent == null) {
                        //
                        // New Root domain
                        //
                        createDir = Paths.get(
                                ((XacmlAdminUI) UI.getCurrent()).getUserGitPath().toAbsolutePath().toString(),
                                newSubDomain);
                    } else {
                        //
                        // New subdomain
                        //
                        createDir = Paths.get(parent.getAbsolutePath(), newSubDomain);
                    }
                    try {
                        //
                        // Does the new subdomain exist?
                        //
                        Path newDir;
                        if (Files.exists(createDir)) {
                            //
                            // It already exists
                            //
                            newDir = createDir;
                        } else {
                            //
                            // Create it
                            //
                            newDir = Files.createDirectory(createDir);
                            //
                            // Create empty .gitignore file
                            //
                            Files.createFile(Paths.get(newDir.toString(), ".gitignore"));
                        }
                        //
                        // Setup the TreeTable
                        //
                        File file = newDir.toFile();
                        if (parent == null) {
                            Item item = self.treeWorkspace.addItem(file);
                            if (item != null) {
                                self.treeWorkspace.setCollapsed(file, false);
                                self.treeWorkspace.select(file);
                            }
                        } else {
                            Item item = self.treeWorkspace.addItem(file);
                            if (item != null) {
                                self.treeWorkspace.setParent(file, parent);
                                self.treeWorkspace.setCollapsed(parent, false);
                                self.treeWorkspace.select(file);
                            }
                        }
                    } catch (IOException e) {
                        logger.error("Failed to create subdomain: " + createDir.toString(), e);
                    }
                } else {
                    //
                    // Get our paths
                    //
                    Path oldDir = Paths.get(parent.getAbsolutePath(), subdomain);
                    Path newDir = Paths.get(parent.getAbsolutePath(), newSubDomain);
                    try {
                        //
                        // Rename the subdomain
                        //
                        Files.move(oldDir, newDir);
                        //
                        // Add to the TreeTable
                        //
                        File newFile = newDir.toFile();
                        File oldFile = oldDir.toFile();
                        Item item = self.treeWorkspace.addItem(newFile);
                        if (item != null) {
                            self.treeWorkspace.setChildrenAllowed(newFile, true);
                            //
                            // Make sure its parent is the same as the old one, unless they
                            // renamed the top-level.
                            //
                            Object parent = self.treeWorkspace.getParent(oldFile);
                            if (parent != null) {
                                self.treeWorkspace.setParent(newFile, parent);
                            }
                            //
                            // Make any children of the old subdomain now children
                            // of the new subdomain.
                            //
                            Collection<?> children = self.treeWorkspace.getChildren(oldFile);
                            Iterator<?> iter = children.iterator();
                            while (iter.hasNext()) {
                                Object child = iter.next();
                                self.treeWorkspace.setParent(child, newFile);
                            }
                            //
                            // Finally remove the old subdomain
                            //
                            self.treeWorkspace.removeItem(oldFile);
                        }
                    } catch (IOException e) {
                        logger.error(
                                "Failed to rename subdomain: " + oldDir.toString() + " to: " + newDir.toString(),
                                e);
                    }
                }
            }
        });
        editor.center();
        UI.getCurrent().addWindow(editor);
    }

    protected void deleteSubDomain(final File subdomain) {
        String message = "Are you sure you want to delete subdomain\n" + subdomain.getName()
                + "\nThis will remove <B>ALL</B> of its subdomains and policy files.";
        ConfirmDialog dialog = ConfirmDialog.getFactory().create("Confirm SubDomain Deletion", message, "Delete",
                "Cancel");
        dialog.setContentMode(ContentMode.HTML);
        dialog.show(getUI(), new ConfirmDialog.Listener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClose(ConfirmDialog dialog) {
                if (dialog.isConfirmed()) {
                    //
                    // Iterate the subdomain
                    //
                    try {
                        Files.walkFileTree(Paths.get(subdomain.getAbsolutePath()), new SimpleFileVisitor<Path>() {
                            @Override
                            public FileVisitResult visitFile(Path deleteFile, BasicFileAttributes attrs)
                                    throws IOException {
                                try {
                                    boolean removeFromTree = deleteFile.getFileName().toString().endsWith(".xml");
                                    Files.delete(deleteFile);
                                    if (removeFromTree) {
                                        self.treeWorkspace.removeItem(deleteFile.toFile());
                                    }
                                    if (logger.isDebugEnabled()) {
                                        logger.debug("Deleted file: " + deleteFile.toString());
                                    }
                                } catch (IOException e) {
                                    logger.error("Failed to delete file: " + deleteFile.toString(), e);
                                    return FileVisitResult.TERMINATE;
                                }
                                return super.visitFile(deleteFile, attrs);
                            }

                            @Override
                            public FileVisitResult postVisitDirectory(Path dir, IOException exc)
                                    throws IOException {
                                try {
                                    Files.delete(dir);
                                    self.treeWorkspace.removeItem(dir.toFile());
                                    if (logger.isDebugEnabled()) {
                                        logger.debug("Deleted dir: " + dir.toString());
                                    }
                                } catch (IOException e) {
                                    logger.error("Failed to delete directory: " + dir.toString(), e);
                                    return FileVisitResult.TERMINATE;
                                }
                                return super.postVisitDirectory(dir, exc);
                            }

                        });
                    } catch (IOException e) {
                        logger.error("Failed to walk subdomain: " + subdomain.getAbsolutePath(), e);
                    }
                }
            }

        }, true);

    }

    protected void createPolicy(final File parentDirectory) {
        //
        // Construct our parameters
        //
        Path parent = Paths.get(parentDirectory.getAbsolutePath());
        Path newFile = this.getNextFilename(parent, "Policy");
        //
        // Run the window
        //
        this.runPolicyWindow("Create New Policy", parent, newFile, null, null);
    }

    protected void renamePolicy(final File policy) {
        //
        // Run the rename window
        //
        final RenamePolicyFileWindow window = new RenamePolicyFileWindow(policy.getName());
        window.setCaption("Rename Policy");
        window.setModal(true);
        window.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent event) {
                String newFilename = window.getNewFilename();
                if (newFilename == null) {
                    //
                    // User cancelled
                    //
                    return;
                }
                Path newPolicy = Paths.get(policy.getParent(), newFilename);
                if (Files.exists(newPolicy)) {
                    Notification.show("Cannot rename to an existing file", Notification.Type.ERROR_MESSAGE);
                    return;
                }
                try {
                    if (policy.renameTo(newPolicy.toFile()) == false) {
                        throw new Exception("No known error, rename failed");
                    }
                    self.treeContainer.updateItem(newPolicy.getParent().toFile());
                } catch (Exception e) {
                    Notification.show("Failed to rename file: " + e.getLocalizedMessage());
                }
            }
        });
        window.center();
        UI.getCurrent().addWindow(window);
    }

    protected void clonePolicy(final File policy) {
        //
        // Figure out a new name for the cloned policy
        //
        Path policyClone = Paths.get(policy.getAbsolutePath());
        Path newFile = this.getNextFilename(policyClone.getParent(), policy.getName());
        if (newFile == null) {
            return;
        }
        //
        // Scan the policy in, replace policy ID's and rule ID's
        //
        Object policyData = new XACMLPolicyScanner(policyClone, new XACMLPolicyScanner.SimpleCallback() {

            @Override
            public CallbackResult onPreVisitRule(PolicyType parent, RuleType rule) {
                rule.setRuleId(((XacmlAdminUI) getUI()).newRuleID());
                return CallbackResult.CONTINUE;
            }

            @Override
            public CallbackResult onPreVisitPolicySet(PolicySetType parent, PolicySetType policySet) {
                policySet.setPolicySetId(((XacmlAdminUI) getUI()).newPolicyID());
                policySet.setVersion("1");
                return CallbackResult.CONTINUE;
            }

            @Override
            public CallbackResult onPreVisitPolicy(PolicySetType parent, PolicyType policy) {
                policy.setPolicyId(((XacmlAdminUI) getUI()).newPolicyID());
                policy.setVersion("1");
                return CallbackResult.CONTINUE;
            }

        }).scan();
        //
        // Run the window
        //
        this.runPolicyWindow("Clone Policy", newFile.getParent(), newFile.getFileName(), policyData, null);
    }

    protected void runPolicyWindow(String caption, final Path parentPath, final Path policyPath,
            final Object policyData, final Path oldPolicyFile) {
        //
        // Create our editor window
        //
        final PolicyNameEditorWindow editor = new PolicyNameEditorWindow(
                (policyPath != null ? policyPath.getFileName().toString() : null), policyData,
                ((XacmlAdminUI) getUI()).getPolicyAlgorithms(), ((XacmlAdminUI) getUI()).getRuleAlgorithms());
        editor.setCaption(caption);
        editor.setCloseShortcut(KeyCode.ESCAPE);
        editor.setModal(true);
        editor.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent event) {
                //
                // Did the user hit save button or esc?
                //
                if (editor.isSaved() == false) {
                    return;
                }
                final Object data = editor.getPolicyData();
                String filename = editor.getPolicyFilename();
                if (filename == null || data == null) {
                    logger.warn("Editor said is was saved but filename/data is null.");
                    return;
                }
                //
                // Determine new path
                //
                final Path newPolicyPath = Paths.get(parentPath.toString(), filename);
                //
                // Is it ok to overwrite the new file?
                //
                try {
                    //
                    // Handle if we are not replacing an old file and we are overwriting
                    // an existing file.
                    //
                    if (self.isOverwritingAPolicy(newPolicyPath, oldPolicyFile) == false
                            && Files.exists(newPolicyPath)) {
                        //
                        // Confirm they wanted to do this, and figure out
                        // new version number.
                        //
                        String message = "You are overwriting a file: " + newPolicyPath.getFileName().toString();
                        ConfirmDialog dialog = ConfirmDialog.getFactory().create("Confirm Policy File Overwriting",
                                message, "Overwrite", "Cancel");
                        dialog.setData(false);
                        dialog.setContentMode(ContentMode.HTML);
                        dialog.setModal(true);
                        dialog.show(getUI(), new ConfirmDialog.Listener() {
                            private static final long serialVersionUID = 1L;

                            @Override
                            public void onClose(ConfirmDialog dialog) {
                                if (dialog.isConfirmed()) {
                                    //
                                    // Yep the user wants to overwrite it
                                    //
                                    self.savePolicy(newPolicyPath, data, oldPolicyFile);
                                    //
                                    // Open it for editing
                                    //
                                    self.openPolicyTab(newPolicyPath.toFile(), false);
                                }
                            }

                        }, true);
                        //
                        // Exit out of this thread
                        //
                        return;
                    }
                } catch (Exception e) {
                    logger.error(e);
                    return;
                }
                //
                // Save it off
                //
                self.savePolicy(newPolicyPath, data, oldPolicyFile);
                //
                // Open it for editing
                //
                self.openPolicyTab(newPolicyPath.toFile(), false);
            }
        });
        editor.center();
        UI.getCurrent().addWindow(editor);
    }

    protected Path getNextFilename(Path parent, String filename) {
        filename = FilenameUtils.removeExtension(filename);
        Path newFile = null;
        int i = 0;
        while (true) {
            newFile = Paths.get(parent.toString(), String.format("%s(%02d)", filename, i++) + ".xml");
            if (Files.notExists(newFile)) {
                return newFile;
            }
            if (i == 100) {
                logger.error("Could not construct a new name for cloned policy.");
                return null;
            }
        }

    }

    protected boolean isOverwritingAPolicy(Path newPolicyPath, Path oldPolicyPath) throws Exception {
        //
        // Check to see if we were editing an existing file. Then check if the
        // new file actually exists. Then check if we are overwriting the original old file
        //
        if (oldPolicyPath != null && Files.exists(newPolicyPath)
                && Files.isSameFile(newPolicyPath, oldPolicyPath)) {
            //
            // Yes its the same, overwriting it is expected.
            //
            logger.info("isOverwritingAPolicy");
            return true;
        }
        return false;
    }

    protected void savePolicy(final Path newPolicyPath, final Object policyData, Path oldPolicyPath) {
        //
        // Are they overwriting another policy?
        //
        String version = "1.0";
        boolean delete = false;
        if (oldPolicyPath != null) {
            //
            // This policy name was being edited. Is it still the same?
            //
            try {
                delete = true;
                if (Files.exists(newPolicyPath) && Files.isSameFile(newPolicyPath, oldPolicyPath)) {
                    delete = false;
                }
            } catch (Exception e) {
                logger.error("Could not determine if same file", e);
                return;
            }
            logger.info("Deleting old file: " + delete);
        }
        //
        // Are we now overwriting another file?
        //
        if (Files.exists(newPolicyPath)) {
            //
            // Yes
            //
            logger.info("Overwriting file");
            //
            // Overwrite is happening. Bump the version (IF WE CAN)
            //
            //TODO - What if user wants to change something other than the last number?  For example, changing 1.5.23 to 2.0.0.
            //TODO     We need a mechanism that allows the user to specify the new policy version (disallowing backtracking) if they desire
            //TODO     and get that new number (if any) passed down to here.  This code then becomes the "then" branch of "If new version has been specified..."
            try {
                int[] versionArray = StdPDPPolicy
                        .versionStringToArray(XACMLPolicyScanner.getVersion(newPolicyPath));
                // increment the right-most digit
                versionArray[versionArray.length - 1]++;
                version = StdPDPPolicy.versionArrayToString(versionArray);
            } catch (NumberFormatException | IOException e) {
                try {
                    logger.warn("Previous version '" + XACMLPolicyScanner.getVersion(newPolicyPath)
                            + "' not a series of itegers");
                } catch (IOException e1) {
                    logger.error("could not get previous version");
                }
                //TODO - This may not be wise since the intent is to increase the version number.  Perhaps we should abort this an go back to the user?
                version = "1.0";
            }
            if (policyData instanceof PolicySetType) {
                ((PolicySetType) policyData).setVersion(version);
            } else if (policyData instanceof PolicyType) {
                ((PolicyType) policyData).setVersion(version);
            }
        } else {
            //
            // Nope, a completely new file
            //
            logger.info("New file");
        }
        //
        // Is the root a PolicySet or Policy?
        //
        Path finalPolicyPath;
        if (policyData instanceof PolicySetType) {
            //
            // Write it out
            //
            finalPolicyPath = XACMLPolicyWriter.writePolicyFile(newPolicyPath, (PolicySetType) policyData);
        } else if (policyData instanceof PolicyType) {
            //
            // Write it out
            //
            finalPolicyPath = XACMLPolicyWriter.writePolicyFile(newPolicyPath, (PolicyType) policyData);
        } else {
            logger.error("Unknown data type sent back.");
            return;
        }
        //
        // Did it get written?
        //
        if (finalPolicyPath == null || !Files.exists(finalPolicyPath)) {
            logger.error("Failed to write policy file.");
            return;
        }
        //
        // Add it into our tree
        //
        this.addPolicyFileToTree(finalPolicyPath.getParent().toFile(), finalPolicyPath.toFile());
        //
        // Do we need to delete the old file?
        //
        if (oldPolicyPath != null && delete) {
            try {
                Files.delete(oldPolicyPath);
            } catch (Exception e) {
                logger.error("Failed to delete old policy", e);
            }
            if (self.treeWorkspace.removeItem(oldPolicyPath.toFile()) == false) {
                logger.warn("Failed to remove old policy path");
            }
        }
    }

    protected void deletePolicy(final File policy) {
        String message = "Are you sure you want to delete policy: " + policy.getName();
        ConfirmDialog dialog = ConfirmDialog.getFactory().create("Confirm Policy File Deletion", message, "Delete",
                "Cancel");
        dialog.setContentMode(ContentMode.HTML);
        dialog.show(getUI(), new ConfirmDialog.Listener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClose(ConfirmDialog dialog) {
                if (dialog.isConfirmed() && policy.delete()) {
                    self.treeWorkspace.removeItem(policy);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Deleted file: " + policy.toString());
                    }
                }
            }

        }, true);

    }

    protected void importPolicy(final File domain) {
        //
        // Get the current domain
        //
        if (!domain.isDirectory()) {
            logger.error("Table must have a directory selected to import the file.");
            return;
        }
        //
        // Create the upload window
        //
        final PolicyUploadWindow upload = new PolicyUploadWindow(Paths.get(domain.toURI()));
        upload.setCaption("Import Xacml 3.0 Policy File");
        upload.setCloseShortcut(KeyCode.ESCAPE);
        upload.setModal(true);
        upload.addCloseListener(new CloseListener() {
            private static final long serialVersionUID = 1L;

            @Override
            public void windowClose(CloseEvent e) {
                //
                // Was it successful?
                //
                Path newFile = upload.getUploadedFile();
                if (newFile == null) {
                    return;
                }
                //
                // Add it
                //
                self.addPolicyFileToTree(domain, newFile.toFile());
                //
                // Are we importing anything in the policy file?
                //
                boolean importAttributes = upload.importAttributes();
                boolean importObligations = upload.importObligations();
                boolean importAdvice = upload.importAdvice();
                if (importAttributes || importObligations || importAdvice) {
                    //
                    // Create our importer
                    //
                    XACMLPolicyImporter importer = new XACMLPolicyImporter();
                    importer.setImportAttributes(importAttributes);
                    importer.setImportObligations(importObligations);
                    importer.setImportAdvice(importAdvice);
                    importer.setIgnoreStandardAttributes(upload.ignoreStandard());
                    //
                    // Yes load and scan the policy
                    //
                    new XACMLPolicyScanner(newFile, importer).scan();
                }
            }
        });
        upload.center();
        UI.getCurrent().addWindow(upload);
    }

    protected void addPolicyFileToTree(File domain, File file) {
        //
        // Add it into our tree
        //
        if (this.treeWorkspace.addItem(file) != null) {
            //
            // Make sure it has the right parent
            //
            this.treeWorkspace.setParent(file, domain);
            //
            // Select our new policy
            //
            self.treeWorkspace.select(file);
        } else {
            logger.error("Failed to add policy to workspace tree");
        }
    }

    /*
    protected void   publishPolicy(final File policy) {
       //
       // Get its ID
       //
       Item item = this.treeContainer.getItem(policy);
       if (item == null) {
     logger.error("Failed to get the item");
     return;
       }
       Object policyData = item.getItemProperty("Data");
       if (policyData == null) {
     logger.error("Failed to get item data property.");
     return;
       }
       String fullId = XACMLPolicyScanner.getID(policyData);
       String version = XACMLPolicyScanner.getVersion(policyData);
       if (fullId == null || version == null) {
     logger.error("Failed to get policy Id");
     return;
       }
       List<String> ids = Lists.newArrayList(Splitter.on(':').split(fullId));
       if (ids.isEmpty()) {
     logger.error("Couldn't parse policy Id");
     return;
       }
       final String id = ids.get(ids.size() - 1) + "." + version;
       //
       // Is there only one group?
       //
       PAPEngine engine = ((XacmlAdminUI)getUI()).getPAPEngine();
       Set<PDPGroup> groups;
       PDPGroup defaultGroup;
       try {
     groups = engine.getPDPGroups();
       } catch (PAPException e) {
     String message = "Unable to retrieve Groups from server: " + e;
     logger.error(message, e);
     throw new RuntimeException(message);
       }
       try {
     defaultGroup = engine.getDefaultGroup();
       } catch (PAPException e) {
     String message = "Unable to retrieve Default Group from server: " + e;
     logger.error(message, e);
     throw new RuntimeException(message);
       }
       if (groups.size() == 1) {
     this.doPublish(id, policy, defaultGroup);
     return;
       }
       //
       // Have user select a group
       //
       final SelectPDPGroupWindow window = new SelectPDPGroupWindow(groups, "Select PDP Group to publish in");
       window.setCaption("Select PDP Group");
       window.setCloseShortcut(KeyCode.ESCAPE);
       window.setModal(true);
       window.addCloseListener(new CloseListener() {
     private static final long serialVersionUID = 1L;
         
     @Override
     public void windowClose(CloseEvent event) {
        PDPGroup group = window.selectedGroup();
        if (group != null) {
           self.doPublish(id, policy, group);
        }
     }
       });
       window.center();
       UI.getCurrent().addWindow(window);
        
    }
        
    protected void   doPublish(String id, File policy, PDPGroup group) {
       //
       // The policy status must be up-to-date
       //
       // TODO
           
       //
       // TODO - get list of referenced policies and publish
       // them first.
       //
           
       //
       // Publish the policy
       //
           
       PAPEngine engine = ((XacmlAdminUI)getUI()).getPAPEngine();
       try (InputStream is = new FileInputStream(policy)) {
     engine.publishPolicy(id, policy.getName(), true, is, group);
       } catch (PAPException | IOException e) {
     logger.error("Failed to publish policy: ", e);
       }
    }
    */

    protected void pushChanges(final File target) {
        try {
            //
            // Grab our working repository
            //
            Path repoPath = ((XacmlAdminUI) getUI()).getUserGitPath();
            final Git git = Git.open(repoPath.toFile());
            //
            // Get our status
            //
            final String base;
            Status status;
            if (target == null) {
                base = ".";
            } else {
                Path relativePath = repoPath.relativize(Paths.get(target.getPath()));
                base = relativePath.toString();
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Status on base: " + base);
            }
            status = git.status().addPath(base).call();
            //
            // Check if its clean
            //
            if (status.isClean()) {
                //
                // Its clean
                //
                AdminNotification.warn(target.getName() + " is clean!");
                return;
            }
            //
            // Create the window
            //
            final GitPushWindow window = new GitPushWindow(git, target, status);
            window.setCaption("Push Changes");
            window.setModal(true);
            window.addCloseListener(new CloseListener() {
                private static final long serialVersionUID = 1L;

                @Override
                public void windowClose(CloseEvent e) {
                    if (window.isSaved() == false) {
                        return;
                    }
                    try {
                        //
                        // Needs to be added first
                        //
                        DirCache cache = git.add().addFilepattern(base).call();
                        for (int i = 0; i < cache.getEntryCount(); i++) {
                            DirCacheEntry entry = cache.getEntry(i);
                            if (logger.isDebugEnabled()) {
                                logger.debug("Entry: " + entry);
                            }
                        }
                        //
                        // Next they need to be committed
                        //
                        RevCommit rev = git.commit().setMessage(window.getComment()).call();
                        if (logger.isDebugEnabled()) {
                            logger.debug("RevCommit: " + rev);
                        }
                        //
                        // Now we can push changes to the Git repository
                        //
                        Iterable<PushResult> results = git.push().call();
                        for (PushResult result : results) {
                            logger.info(result);
                        }
                        //
                        // Have the container fire an item set change notification
                        //
                        self.treeContainer.updateItem(target);
                    } catch (NoWorkTreeException | GitAPIException e1) {
                        logger.error(e);
                        AdminNotification.error("Exception occurred while trying to push: " + e1);
                    }
                }

            });
            window.center();
            UI.getCurrent().addWindow(window);
        } catch (IOException | GitAPIException e) {
            logger.error(e);
            AdminNotification.error("Exception occurred while trying to get status: " + e);
        }
    }

    protected void synchronizeRepository() {
        final GitSynchronizeWindow window = new GitSynchronizeWindow();
        window.setCaption("Synchronize with server repository?");
        window.setModal(true);
        window.center();
        UI.getCurrent().addWindow(window);
    }

    protected void exportRepository() {
        this.buttonExport.click();
    }

    @Override
    public String getFilename() {
        return "Repository.tgz";
    }

    @Override
    public InputStream getStream() {
        //
        // Grab our working repository
        //
        final Path repoPath = ((XacmlAdminUI) getUI()).getUserGitPath();
        Path workspacePath = ((XacmlAdminUI) getUI()).getUserWorkspace();
        final Path tarFile = Paths.get(workspacePath.toString(), "Repository.tgz");

        try (OutputStream os = Files.newOutputStream(tarFile)) {
            try (GzipCompressorOutputStream gzOut = new GzipCompressorOutputStream(os)) {
                try (TarArchiveOutputStream tarOut = new TarArchiveOutputStream(gzOut)) {

                    tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);

                    Files.walkFileTree(repoPath, new SimpleFileVisitor<Path>() {

                        @Override
                        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                                throws IOException {
                            if (dir.getFileName().toString().startsWith(".git")) {
                                return FileVisitResult.SKIP_SUBTREE;
                            }
                            Path relative = repoPath.relativize(dir);
                            if (relative.toString().isEmpty()) {
                                return super.preVisitDirectory(dir, attrs);
                            }
                            TarArchiveEntry entry = new TarArchiveEntry(relative.toFile());
                            tarOut.putArchiveEntry(entry);
                            tarOut.closeArchiveEntry();
                            return super.preVisitDirectory(dir, attrs);
                        }

                        @Override
                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                            if (file.getFileName().toString().endsWith(".xml") == false) {
                                return super.visitFile(file, attrs);
                            }
                            Path relative = repoPath.relativize(file);
                            TarArchiveEntry entry = new TarArchiveEntry(relative.toFile());
                            entry.setSize(Files.size(file));
                            tarOut.putArchiveEntry(entry);
                            try {
                                IOUtils.copy(Files.newInputStream(file), tarOut);
                            } catch (IOException e) {
                                logger.error(e);
                            }
                            tarOut.closeArchiveEntry();
                            return super.visitFile(file, attrs);
                        }

                    });
                    tarOut.finish();
                }
            }
        } catch (IOException e) {
            logger.error(e);
        }
        try {
            return Files.newInputStream(tarFile);
        } catch (IOException e) {
            logger.error(e);
        }
        return null;
    }

    protected void openPolicyTab(File policy, boolean readOnly) {
        //
        // Sanity check
        //
        assert policy != null;
        assert policy.isFile();
        if (policy == null || !policy.isFile()) {
            throw new IllegalArgumentException("You must specify a file.");
        }
        Status status;
        Path relativePath;
        String base;
        try {
            //
            // Grab our working repository
            //
            Path repoPath = ((XacmlAdminUI) getUI()).getUserGitPath();
            final Git git = Git.open(repoPath.toFile());
            //
            // Get our status
            //
            relativePath = repoPath.relativize(Paths.get(policy.getPath()));
            base = relativePath.toString();
            if (logger.isDebugEnabled()) {
                logger.debug("Status on base: " + base);
            }
            status = git.status().addPath(base).call();
        } catch (NoWorkTreeException | IOException | GitAPIException e) {
            logger.error("Failed to get status on " + policy + " " + e);
            AdminNotification.error("Could not get Git status on the file.");
            return;
        }
        //
        // Check if its clean
        //
        if (status.isClean() == false) {
            //
            // Check if its conflicting
            //
            for (String conflict : status.getConflicting()) {
                if (conflict.equals(base)) {
                    //
                    // Yes - we won't be able to edit it
                    //
                    AdminNotification.error("Policy has conflicts with master, please synchronize the repository.");
                    return;
                }
            }
        }
        //
        // Check to see if there already is a tab open
        //
        Iterator<Component> iter = self.tabSheet.iterator();
        while (iter.hasNext()) {
            Component c = iter.next();
            if (c instanceof PolicyEditor) {
                Object data = ((PolicyEditor) c).getData();
                if (data != null && data instanceof File && ((File) data).equals(policy)) {
                    self.tabSheet.setSelectedTab(c);
                    return;
                }
            }
        }
        //
        // No tab is open, create a new one
        //
        PolicyEditor editor = null;
        try {
            editor = new PolicyEditor(policy, this.treeContainer, readOnly);
        } catch (IOException e) {
            logger.error("Failed to open policy");
            editor = null;
        }
        if (editor != null) {
            editor.setWidth("100%");
            Tab tab = self.tabSheet.addTab(editor);
            editor.setTab(tab);
            tab.setClosable(true);

            self.tabSheet.setSelectedTab(editor);
        } else {
            AdminNotification.error("The Policy File is not a Xacml 3.0 policy.");
        }
    }

    @Override
    public void drop(DragAndDropEvent event) {
        Transferable t = event.getTransferable();
        Component source = t.getSourceComponent();
        if (source != this.treeWorkspace) {
            assert false;
            throw new IllegalArgumentException();
        }
        TableTransferable tt = (TableTransferable) t;
        File sourceFile = (File) tt.getItemId();

        AbstractSelectTargetDetails target = (AbstractSelectTargetDetails) event.getTargetDetails();
        File targetFile = (File) target.getItemIdOver();

        if (sourceFile.isFile() && targetFile != null && targetFile.isDirectory()) {
            //
            // Construct destination filename
            //
            Path dest = targetFile.toPath().resolve(sourceFile.getName());
            //
            // Check if the target domain exists
            //
            if (Files.exists(dest)) {
                //
                // Prompt the user
                //
                Notification.show("A policy file with that name already exists in that directory.",
                        Notification.Type.ERROR_MESSAGE);
            } else {
                //
                // Go ahead and rename it
                //
                this.renamePolicyFile(sourceFile, dest.toFile(), targetFile);
            }
        }
    }

    protected void renamePolicyFile(File sourceFile, File dest, File parent) {
        try {
            if (sourceFile.renameTo(dest)) {
                this.treeContainer.setParent(sourceFile, parent);
                this.treeContainer.updateItem(parent);
            }
        } catch (Exception e) {
            String error = "Failed to rename " + sourceFile + " to: " + dest + System.lineSeparator()
                    + e.getLocalizedMessage();
            logger.error(error);
            AdminNotification.error(error);
        }
    }

    @Override
    public AcceptCriterion getAcceptCriterion() {
        return AcceptAll.get();
    }

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

        // top-level component properties
        setWidth("100.0%");
        setHeight("100.0%");

        // horizontalSplitPanel
        horizontalSplitPanel = buildHorizontalSplitPanel();
        mainLayout.addComponent(horizontalSplitPanel);
        mainLayout.setExpandRatio(horizontalSplitPanel, 1.0f);

        return mainLayout;
    }

    @AutoGenerated
    private HorizontalSplitPanel buildHorizontalSplitPanel() {
        // common part: create layout
        horizontalSplitPanel = new HorizontalSplitPanel();
        horizontalSplitPanel.setImmediate(false);
        horizontalSplitPanel.setWidth("100.0%");
        horizontalSplitPanel.setHeight("100.0%");

        // verticalLayoutLeftPanel
        verticalLayoutLeftPanel = buildVerticalLayoutLeftPanel();
        horizontalSplitPanel.addComponent(verticalLayoutLeftPanel);

        // verticalLayoutRightPanel
        verticalLayoutRightPanel = buildVerticalLayoutRightPanel();
        horizontalSplitPanel.addComponent(verticalLayoutRightPanel);

        return horizontalSplitPanel;
    }

    @AutoGenerated
    private VerticalLayout buildVerticalLayoutLeftPanel() {
        // common part: create layout
        verticalLayoutLeftPanel = new VerticalLayout();
        verticalLayoutLeftPanel.setImmediate(false);
        verticalLayoutLeftPanel.setWidth("100.0%");
        verticalLayoutLeftPanel.setHeight("100.0%");
        verticalLayoutLeftPanel.setMargin(true);
        verticalLayoutLeftPanel.setSpacing(true);

        // horizontalLayoutLeftToolbar
        horizontalLayoutLeftToolbar = buildHorizontalLayoutLeftToolbar();
        verticalLayoutLeftPanel.addComponent(horizontalLayoutLeftToolbar);

        // treeWorkspace
        treeWorkspace = new TreeTable();
        treeWorkspace.setImmediate(true);
        treeWorkspace.setWidth("100.0%");
        treeWorkspace.setHeight("100.0%");
        verticalLayoutLeftPanel.addComponent(treeWorkspace);
        verticalLayoutLeftPanel.setExpandRatio(treeWorkspace, 1.0f);

        return verticalLayoutLeftPanel;
    }

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

        // horizontalLayoutLeftToolbarLeft
        horizontalLayoutLeftToolbarLeft = buildHorizontalLayoutLeftToolbarLeft();
        horizontalLayoutLeftToolbar.addComponent(horizontalLayoutLeftToolbarLeft);

        // buttonLeft
        buttonLeft = new Button();
        buttonLeft.setCaption("<<");
        buttonLeft.setImmediate(true);
        buttonLeft.setDescription("Minimize left panel.");
        buttonLeft.setWidth("-1px");
        buttonLeft.setHeight("-1px");
        horizontalLayoutLeftToolbar.addComponent(buttonLeft);
        horizontalLayoutLeftToolbar.setComponentAlignment(buttonLeft, new Alignment(34));

        return horizontalLayoutLeftToolbar;
    }

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

        // buttonSynchronize
        buttonSynchronize = new Button();
        buttonSynchronize.setCaption("Synchronize Repository");
        buttonSynchronize.setImmediate(true);
        buttonSynchronize.setDescription("Synchronize local repository with main branch.");
        buttonSynchronize.setWidth("-1px");
        buttonSynchronize.setHeight("-1px");
        horizontalLayoutLeftToolbarLeft.addComponent(buttonSynchronize);

        // buttonExport
        buttonExport = new Button();
        buttonExport.setCaption("Export Workspace");
        buttonExport.setImmediate(true);
        buttonExport.setDescription("Export your workspace to your local drive.");
        buttonExport.setWidth("-1px");
        buttonExport.setHeight("-1px");
        horizontalLayoutLeftToolbarLeft.addComponent(buttonExport);

        return horizontalLayoutLeftToolbarLeft;
    }

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

        // horizontalLayoutRightToolbar
        horizontalLayoutRightToolbar = buildHorizontalLayoutRightToolbar();
        verticalLayoutRightPanel.addComponent(horizontalLayoutRightToolbar);

        // tabSheet
        tabSheet = new TabSheet();
        tabSheet.setImmediate(true);
        tabSheet.setWidth("100.0%");
        tabSheet.setHeight("-1px");
        verticalLayoutRightPanel.addComponent(tabSheet);
        verticalLayoutRightPanel.setExpandRatio(tabSheet, 1.0f);

        return verticalLayoutRightPanel;
    }

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

        // buttonRight
        buttonRight = new Button();
        buttonRight.setCaption(">>");
        buttonRight.setImmediate(true);
        buttonRight.setDescription("Restore left panel.");
        buttonRight.setWidth("-1px");
        buttonRight.setHeight("-1px");
        horizontalLayoutRightToolbar.addComponent(buttonRight);

        return horizontalLayoutRightToolbar;
    }
}