gt:             if (hasCreatePermission()) {
context: /**
   * Copyright (c) 2015 Bosch Software Innovations GmbH and others.
   *
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   */
  package org.eclipse.hawkbit.ui.common;
  
  import java.util.List;
  import java.util.Set;
  
  import javax.annotation.PostConstruct;
  
  import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
  import org.eclipse.hawkbit.repository.model.MetaData;
  import org.eclipse.hawkbit.repository.model.NamedVersionedEntity;
  import org.eclipse.hawkbit.ui.common.CommonDialogWindow.SaveDialogCloseListener;
  import org.eclipse.hawkbit.ui.common.builder.LabelBuilder;
  import org.eclipse.hawkbit.ui.common.builder.TextAreaBuilder;
  import org.eclipse.hawkbit.ui.common.builder.TextFieldBuilder;
  import org.eclipse.hawkbit.ui.common.builder.WindowBuilder;
  import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
  import org.eclipse.hawkbit.ui.customrenderers.renderers.HtmlButtonRenderer;
  import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
  import org.eclipse.hawkbit.ui.utils.HawkbitCommonUtil;
  import org.eclipse.hawkbit.ui.utils.I18N;
  import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider;
  import org.eclipse.hawkbit.ui.utils.SPUIDefinitions;
  import org.eclipse.hawkbit.ui.utils.SPUIStyleDefinitions;
  import org.eclipse.hawkbit.ui.utils.UINotification;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.vaadin.spring.events.EventBus;
  
  import com.vaadin.data.Item;
  import com.vaadin.data.util.IndexedContainer;
  import com.vaadin.event.FieldEvents.TextChangeEvent;
  import com.vaadin.event.SelectionEvent;
  import com.vaadin.server.FontAwesome;
  import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
  import com.vaadin.ui.Alignment;
  import com.vaadin.ui.Button;
  import com.vaadin.ui.CustomComponent;
  import com.vaadin.ui.Grid;
  import com.vaadin.ui.Grid.SelectionMode;
  import com.vaadin.ui.HorizontalLayout;
  import com.vaadin.ui.Label;
  import com.vaadin.ui.TextArea;
  import com.vaadin.ui.TextField;
  import com.vaadin.ui.UI;
  import com.vaadin.ui.VerticalLayout;
  import com.vaadin.ui.renderers.ClickableRenderer.RendererClickEvent;
  
  /**
   * 
   * Abstract pop up layout
   *
   * @param <E>
   *            E id the entity for which metadata is displayed
   * @param <M>
   *            M is the metadata
   * 
   */
  public abstract class AbstractMetadataPopupLayout<E extends NamedVersionedEntity, M extends MetaData>
          extends CustomComponent {
  
      private static final String DELETE_BUTTON = "DELETE_BUTTON";
  
      private static final long serialVersionUID = -1491218218453167613L;
  
      private static final String VALUE = "value";
  
      private static final String KEY = "key";
  
      @Autowired
      protected I18N i18n;
  
      @Autowired
      private UINotification uiNotification;
  
      @Autowired
      protected transient EventBus.SessionEventBus eventBus;
  
      private TextField keyTextField;
  
      private TextArea valueTextArea;
  
      private Button addIcon;
  
      private Grid metaDataGrid;
  
      private Label headerCaption;
  
      private CommonDialogWindow metadataWindow;
  
      private E selectedEntity;
  
      private HorizontalLayout mainLayout;
  
      /**
       * Save the metadata and never close the window after saving.
       */
      private final class SaveOnDialogCloseListener implements SaveDialogCloseListener {
          @Override
          public void saveOrUpdate() {
              onSave();
          }
  
          @Override
          public boolean canWindowClose() {
              return false;
          }
  
          @Override
          public boolean canWindowSaveOrUpdate() {
              return true;
          }
  
      }
  
      @PostConstruct
      void init() {
          createComponents();
          buildLayout();
  
      }
  
      /**
       * Returns metadata popup.
       * 
       * @param entity
       *            entity for which metadata data is displayed
       * @param metaData
       *            metadata to be selected
       * @return @link{CommonDialogWindow}
       */
      public CommonDialogWindow getWindow(final E entity, final M metaData) {
          selectedEntity = entity;
          final String nameVersion = HawkbitCommonUtil.getFormattedNameVersion(entity.getName(), entity.getVersion());
  
          metadataWindow = new WindowBuilder(SPUIDefinitions.CREATE_UPDATE_WINDOW)
                  .caption(getMetadataCaption(nameVersion)).content(this).cancelButtonClickListener(event -> onCancel())
                  .id(UIComponentIdProvider.METADATA_POPUP_ID).layout(mainLayout).i18n(i18n)
                  .saveDialogCloseListener(new SaveOnDialogCloseListener()).buildCommonDialogWindow();
  
          metadataWindow.setHeight(550, Unit.PIXELS);
          metadataWindow.setWidth(800, Unit.PIXELS);
          metadataWindow.getMainLayout().setSizeFull();
          metadataWindow.getButtonsLayout().setHeight("45px");
          setUpDetails(entity.getId(), metaData);
          return metadataWindow;
      }
  
      public E getSelectedEntity() {
          return selectedEntity;
      }
  
      public void setSelectedEntity(final E selectedEntity) {
          this.selectedEntity = selectedEntity;
      }
  
      protected abstract void checkForDuplicate(E entity, String value);
  
      protected abstract M createMetadata(E entity, String key, String value);
  
      protected abstract M updateMetadata(E entity, String key, String value);
  
      protected abstract List<M> getMetadataList();
  
      protected abstract void deleteMetadata(E entity, String key, String value);
  
      protected abstract boolean hasCreatePermission();
  
      protected abstract boolean hasUpdatePermission();
  
      private void createComponents() {
          keyTextField = createKeyTextField();
          valueTextArea = createValueTextField();
          metaDataGrid = createMetadataGrid();
          addIcon = createAddIcon();
          headerCaption = createHeaderCaption();
      }
  
      private void buildLayout() {
          final HorizontalLayout headerLayout = new HorizontalLayout();
          headerLayout.addStyleName(SPUIStyleDefinitions.WIDGET_TITLE);
          headerLayout.setSpacing(false);
          headerLayout.setMargin(false);
          headerLayout.setSizeFull();
          headerLayout.addComponent(headerCaption);
          if (hasCreatePermission()) {
              headerLayout.addComponents(addIcon);
              headerLayout.setComponentAlignment(addIcon, Alignment.MIDDLE_RIGHT);
          }
          headerLayout.setExpandRatio(headerCaption, 1.0F);
  
          final HorizontalLayout headerWrapperLayout = new HorizontalLayout();
          headerWrapperLayout.addStyleName("bordered-layout" + " " + "no-border-bottom" + " " + "metadata-table-margin");
          headerWrapperLayout.addComponent(headerLayout);
          headerWrapperLayout.setWidth("100%");
          headerLayout.setHeight("30px");
  
          final VerticalLayout tableLayout = new VerticalLayout();
          tableLayout.setSizeFull();
          tableLayout.setHeight("100%");
          tableLayout.addComponent(headerWrapperLayout);
          tableLayout.addComponent(metaDataGrid);
          tableLayout.addStyleName("table-layout");
          tableLayout.setExpandRatio(metaDataGrid, 1.0F);
  
          final VerticalLayout metadataFieldsLayout = new VerticalLayout();
          metadataFieldsLayout.setSizeFull();
          metadataFieldsLayout.setHeight("100%");
          metadataFieldsLayout.addComponent(keyTextField);
          metadataFieldsLayout.addComponent(valueTextArea);
          metadataFieldsLayout.setSpacing(true);
          metadataFieldsLayout.setExpandRatio(valueTextArea, 1F);
  
          mainLayout = new HorizontalLayout();
          mainLayout.addComponent(tableLayout);
          mainLayout.addComponent(metadataFieldsLayout);
          mainLayout.setExpandRatio(tableLayout, 0.5F);
          mainLayout.setExpandRatio(metadataFieldsLayout, 0.5F);
          mainLayout.setSizeFull();
          mainLayout.setSpacing(true);
          setCompositionRoot(mainLayout);
          setSizeFull();
      }
  
      private TextField createKeyTextField() {
          final TextField keyField = new TextFieldBuilder().caption(i18n.get("textfield.key")).required(true)
                  .prompt(i18n.get("textfield.key")).immediate(true).id(UIComponentIdProvider.METADATA_KEY_FIELD_ID)
                  .maxLengthAllowed(128).buildTextComponent();
          keyField.addTextChangeListener(event -> onKeyChange(event));
          keyField.setTextChangeEventMode(TextChangeEventMode.EAGER);
          keyField.setWidth("100%");
          return keyField;
      }
  
      private TextArea createValueTextField() {
          valueTextArea = new TextAreaBuilder().caption(i18n.get("textfield.value")).required(true)
                  .prompt(i18n.get("textfield.value")).immediate(true).id(UIComponentIdProvider.METADATA_VALUE_ID)
                  .maxLengthAllowed(4000).buildTextComponent();
          valueTextArea.setNullRepresentation("");
          valueTextArea.setSizeFull();
          valueTextArea.setHeight(100, Unit.PERCENTAGE);
          valueTextArea.addTextChangeListener(event -> onValueChange(event));
          valueTextArea.setTextChangeEventMode(TextChangeEventMode.EAGER);
          return valueTextArea;
      }
  
      private Grid createMetadataGrid() {
          final Grid metadataGrid = new Grid();
          metadataGrid.addStyleName(SPUIStyleDefinitions.METADATA_GRID);
          metadataGrid.setImmediate(true);
          metadataGrid.setHeight("100%");
          metadataGrid.setWidth("100%");
          metadataGrid.setId(UIComponentIdProvider.METDATA_TABLE_ID);
          metadataGrid.setSelectionMode(SelectionMode.SINGLE);
          metadataGrid.setColumnReorderingAllowed(true);
          metadataGrid.setContainerDataSource(getMetadataContainer());
          metadataGrid.getColumn(KEY).setHeaderCaption(i18n.get("header.key"));
          metadataGrid.getColumn(VALUE).setHeaderCaption(i18n.get("header.value"));
          metadataGrid.getColumn(VALUE).setHidden(true);
          metadataGrid.addSelectionListener(event -> onRowClick(event));
          metadataGrid.getColumn(DELETE_BUTTON).setHeaderCaption("");
          metadataGrid.getColumn(DELETE_BUTTON).setRenderer(new HtmlButtonRenderer(event -> onDelete(event)));
          metadataGrid.getColumn(DELETE_BUTTON).setWidth(50);
          metadataGrid.getColumn(KEY).setExpandRatio(1);
          return metadataGrid;
      }
  
      private void onDelete(final RendererClickEvent event) {
          final Item item = metaDataGrid.getContainerDataSource().getItem(event.getItemId());
          final String key = (String) item.getItemProperty(KEY).getValue();
          final String value = (String) item.getItemProperty(VALUE).getValue();
  
          final ConfirmationDialog confirmDialog = new ConfirmationDialog(
                  i18n.get("caption.metadata.delete.action.confirmbox"), i18n.get("message.confirm.delete.metadata", key),
                  i18n.get("button.ok"), i18n.get("button.cancel"), ok -> {
                      if (ok) {
                          handleOkDeleteMetadata(event, key, value);
                      }
                  });
          UI.getCurrent().addWindow(confirmDialog.getWindow());
          confirmDialog.getWindow().bringToFront();
      }
  
      private void handleOkDeleteMetadata(final RendererClickEvent event, final String key, final String value) {
          deleteMetadata(getSelectedEntity(), key, value);
          uiNotification.displaySuccess(i18n.get("message.metadata.deleted.successfully", key));
          final Object selectedRow = metaDataGrid.getSelectedRow();
          metaDataGrid.getContainerDataSource().removeItem(event.getItemId());
          // force grid to refresh
          metaDataGrid.clearSortOrder();
          if (!metaDataGrid.getContainerDataSource().getItemIds().isEmpty()) {
              if (selectedRow != null) {
                  if (selectedRow.equals(event.getItemId())) {
                      metaDataGrid.select(metaDataGrid.getContainerDataSource().getIdByIndex(0));
                  } else {
                      metaDataGrid.select(selectedRow);
                  }
              }
          } else {
              clearTextFields();
          }
      }
  
      private void clearTextFields() {
          keyTextField.clear();
          valueTextArea.clear();
          metaDataGrid.select(null);
          if (hasCreatePermission()) {
              keyTextField.setEnabled(true);
              valueTextArea.setEnabled(true);
              addIcon.setEnabled(false);
          }
      }
  
      private Button createAddIcon() {
          addIcon = SPUIComponentProvider.getButton(UIComponentIdProvider.METADTA_ADD_ICON_ID, i18n.get("button.save"),
                  null, null, false, FontAwesome.PLUS, SPUIButtonStyleSmallNoBorder.class);
          addIcon.addClickListener(event -> onAdd());
          return addIcon;
      }
  
      private Label createHeaderCaption() {
          return new LabelBuilder().name(i18n.get("caption.metadata")).buildCaptionLabel();
      }
  
      private static IndexedContainer getMetadataContainer() {
          final IndexedContainer swcontactContainer = new IndexedContainer();
          swcontactContainer.addContainerProperty(KEY, String.class, "");
          swcontactContainer.addContainerProperty(VALUE, String.class, "");
          swcontactContainer.addContainerProperty(DELETE_BUTTON, String.class, FontAwesome.TRASH_O.getHtml());
          return swcontactContainer;
      }
  
      private void popualateKeyValue(final Object metadataCompositeKey) {
          if (metadataCompositeKey != null) {
              final Item item = metaDataGrid.getContainerDataSource().getItem(metadataCompositeKey);
              keyTextField.setValue((String) item.getItemProperty(KEY).getValue());
              valueTextArea.setValue((String) item.getItemProperty(VALUE).getValue());
              keyTextField.setEnabled(false);
              if (hasUpdatePermission()) {
                  valueTextArea.setEnabled(true);
              }
          }
      }
  
      private void populateGrid() {
          final List<M> metadataList = getMetadataList();
          for (final M metaData : metadataList) {
              addItemToGrid(metaData.getKey(), metaData.getValue());
          }
      }
  
      private void addItemToGrid(final String key, final String value) {
          final IndexedContainer metadataContainer = (IndexedContainer) metaDataGrid.getContainerDataSource();
          final Item item = metadataContainer.addItem(key);
          item.getItemProperty(VALUE).setValue(value);
          item.getItemProperty(KEY).setValue(key);
      }
  
      private void updateItemInGrid(final String key) {
          final IndexedContainer metadataContainer = (IndexedContainer) metaDataGrid.getContainerDataSource();
          final Item item = metadataContainer.getItem(key);
          item.getItemProperty(VALUE).setValue(valueTextArea.getValue());
      }
  
      private void onAdd() {
          metaDataGrid.deselect(metaDataGrid.getSelectedRow());
          valueTextArea.clear();
          keyTextField.clear();
          keyTextField.setEnabled(true);
          valueTextArea.setEnabled(true);
          addIcon.setEnabled(true);
      }
  
      private void onSave() {
          final String key = keyTextField.getValue();
          final String value = valueTextArea.getValue();
          if (mandatoryCheck()) {
              final E entity = selectedEntity;
              if (metaDataGrid.getSelectedRow() == null) {
                  if (!duplicateCheck(entity)) {
                      final M metadata = createMetadata(entity, key, value);
                      uiNotification.displaySuccess(i18n.get("message.metadata.saved", metadata.getKey()));
                      addItemToGrid(metadata.getKey(), metadata.getValue());
                      metaDataGrid.scrollToEnd();
                      metaDataGrid.select(metadata.getKey());
                      addIcon.setEnabled(true);
                      metadataWindow.setSaveButtonEnabled(false);
                      if (!hasUpdatePermission()) {
                          valueTextArea.setEnabled(false);
                      }
                  }
              } else {
                  final M metadata = updateMetadata(entity, key, value);
                  uiNotification.displaySuccess(i18n.get("message.metadata.updated", metadata.getKey()));
                  updateItemInGrid(metadata.getKey());
                  metaDataGrid.select(metadata.getKey());
                  addIcon.setEnabled(true);
                  metadataWindow.setSaveButtonEnabled(false);
              }
          }
      }
  
      private boolean mandatoryCheck() {
          if (keyTextField.getValue().isEmpty()) {
              uiNotification.displayValidationError(i18n.get("message.key.missing"));
              return false;
          }
          if (valueTextArea.getValue().isEmpty()) {
              uiNotification.displayValidationError(i18n.get("message.value.missing"));
              return false;
          }
          return true;
      }
  
      private boolean duplicateCheck(final E entity) {
          try {
              checkForDuplicate(entity, keyTextField.getValue());
              // we do not want to log the exception here, does not make sense
          } catch (@SuppressWarnings("squid:S1166") final EntityNotFoundException exception) {
              return false;
          }
          uiNotification.displayValidationError(i18n.get("message.metadata.duplicate.check", keyTextField.getValue()));
          return true;
      }
  
      private String getMetadataCaption(final String nameVersionStr) {
          final StringBuilder caption = new StringBuilder();
          caption.append(HawkbitCommonUtil.DIV_DESCRIPTION_START + i18n.get("caption.metadata.popup") + " "
                  + HawkbitCommonUtil.getBoldHTMLText(nameVersionStr));
          caption.append(HawkbitCommonUtil.DIV_DESCRIPTION_END);
          return caption.toString();
      }
  
      private void onCancel() {
          metadataWindow.close();
          UI.getCurrent().removeWindow(metadataWindow);
      }
  
      private void onKeyChange(final TextChangeEvent event) {
          if (hasCreatePermission() || hasUpdatePermission()) {
              if (!valueTextArea.getValue().isEmpty() && !event.getText().isEmpty()) {
                  metadataWindow.setSaveButtonEnabled(true);
              } else {
                  metadataWindow.setSaveButtonEnabled(false);
              }
          }
      }
  
      private void onRowClick(final SelectionEvent event) {
          final Set<Object> itemsSelected = event.getSelected();
          if (!itemsSelected.isEmpty()) {
              final Object itemSelected = itemsSelected.stream().findFirst().isPresent()
                      ? itemsSelected.stream().findFirst().get() : null;
              popualateKeyValue(itemSelected);
              addIcon.setEnabled(true);
          } else {
              keyTextField.clear();
              valueTextArea.clear();
  