All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tentackle.fx.rdc.security.SecurityEditor Maven / Gradle / Ivy

There is a newer version: 21.16.1.0
Show newest version
/*
 * Tentackle - http://www.tentackle.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the DFree Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.tentackle.fx.rdc.security;

import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;

import org.tentackle.bind.Bindable;
import org.tentackle.fx.Fx;
import org.tentackle.fx.FxControllerService;
import org.tentackle.fx.component.FxButton;
import org.tentackle.fx.component.FxCheckBox;
import org.tentackle.fx.component.FxRadioButton;
import org.tentackle.fx.component.FxTextArea;
import org.tentackle.fx.component.FxTextField;
import org.tentackle.fx.container.FxGridPane;
import org.tentackle.fx.rdc.PdoEditor;
import org.tentackle.pdo.DomainContext;
import org.tentackle.security.Permission;
import org.tentackle.security.SecurityFactory;
import org.tentackle.security.pdo.Security;

import java.net.URL;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeMap;



/**
 * Editor for Security.
 *
 * @author harald
 */
@FxControllerService
public class SecurityEditor extends PdoEditor {

  private static final String DENY_STYLE = "sec-deny";
  private static final String ALLOW_STYLE = "sec-allow";
  private static final String NA_STYLE = "sec-na";

  @Bindable
  private Security sec;

  @FXML
  private FxTextField secGranteeField;
  @FXML
  private FxButton granteeButton;
  @FXML
  private FxTextField secDomainContextObjectField;
  @FXML
  private FxButton contextButton;
  @FXML
  private FxRadioButton allowButton;
  @FXML
  private FxRadioButton denyButton;
  @FXML
  private FxGridPane permissionPane;
  @FXML
  private FxTextArea secMessageField;


  private Class clazz;
  private Map permissionCheckBoxes;
  private Map permissionRadioButtons;



  @Override
  @SuppressWarnings("unchecked")
  public void initialize(URL location, ResourceBundle resources) {
    secGranteeField.setChangeable(false);
    granteeButton.setOnAction(e -> selectGrantee());
    allowButton.setBindable(false);
    denyButton.setBindable(false);
    ToggleGroup group = new ToggleGroup();
    allowButton.setToggleGroup(group);
    allowButton.getStyleClass().add(ALLOW_STYLE);
    denyButton.setToggleGroup(group);
    denyButton.getStyleClass().add(DENY_STYLE);
    group.selectedToggleProperty().addListener(obs -> {
      if (group.getSelectedToggle() == allowButton) {
        sec.setAllowed(true);
      }
      else if (group.getSelectedToggle() == denyButton) {
        sec.setAllowed(false);
      }
      updateEffectivePermissions();
    });
    permissionCheckBoxes = new TreeMap<>();   // sort by name
    permissionRadioButtons = new HashMap<>();
    for (Class permissionIf: SecurityFactory.getInstance().getPermissionInterfaces()) {
      Permission permission = SecurityFactory.getInstance().getPermission(permissionIf);
      FxCheckBox checkBox = Fx.createNode(CheckBox.class);
      checkBox.setText(permission.getName());
      checkBox.setBindable(false);
      checkBox.addViewToModelListener(() -> {
        permissionsToModel();
        updateEffectivePermissions();
      });
      permissionCheckBoxes.put(permission, checkBox);
      FxRadioButton effectiveRadioButton = Fx.createNode(RadioButton.class);
      effectiveRadioButton.setBindable(false);
      effectiveRadioButton.setChangeable(false);
      permissionRadioButtons.put(permission, effectiveRadioButton);
    }
    int row = 1;
    for (Map.Entry entry: permissionCheckBoxes.entrySet()) {
      permissionPane.add(entry.getValue(), 0, row);
      permissionPane.add(permissionRadioButtons.get(entry.getKey()), 1, row);
      row++;
    }

    if (!SecurityDialogFactory.getInstance().isDomainContextUsed()) {
      contextButton.setDisable(true);
      secDomainContextObjectField.setDisable(true);
    }
    else {
      contextButton.setOnAction(e -> selectContext());
    }
  }

  @Override
  public Security getPdo() {
    return sec;
  }

  @Override
  public void setPdo(Security pdo) {
    this.sec = pdo;
    getBinder().putBindingProperty(DomainContext.class, pdo.getDomainContext());
    if (pdo.isAllowed()) {
      allowButton.setSelected(true);
    }
    else {
      denyButton.setSelected(true);
    }
    for (FxCheckBox checkBox: permissionCheckBoxes.values()) {
      checkBox.setSelected(false);
    }
    Class[] permissions = SecurityFactory.getInstance().stringToPermissionInterfaces(pdo.getPermissions());
    for (Class permission : permissions) {
      @SuppressWarnings("unchecked")
      FxCheckBox box = permissionCheckBoxes.get(SecurityFactory.getInstance().getPermission((Class) permission));
      if (box != null) {
        box.setSelected(true);
      }
    }
    getContainer().updateView();
    updateEffectivePermissions();
  }

  /**
   * Sets the securable class.
   *
   * @param clazz the securable class
   */
  public void setSecurableClass(Class clazz) {
    this.clazz = clazz;
    for (Map.Entry entry: permissionCheckBoxes.entrySet()) {
      Permission permission = entry.getKey();
      FxCheckBox box = entry.getValue();
      boolean changeable = permission.appliesTo(clazz);
      box.setChangeable(changeable);
      if (changeable) {
        box.getStyleClass().remove(NA_STYLE);
      }
      else if (!box.getStyleClass().contains(NA_STYLE)) {
        box.getStyleClass().add(NA_STYLE);
      }
    }
  }

  @Override
  public void requestInitialFocus() {
    allowButton.requestFocus();
  }

  @Override
  public void configure() {
  }


  /**
   * Sets the changeability of the editor.
   *
   * @param changeable true if changeable
   */
  @Override
  public void setChangeable(boolean changeable) {
    super.setChangeable(changeable);
    granteeButton.setDisable(!changeable);
  }


  private void selectGrantee() {
    sec.setGrantee(SecurityDialogFactory.getInstance().selectGrantee(getStage(), getDomainContext()));
    secGranteeField.updateView();
    getContainer().getDelegate().fireViewToModelListeners();  // SecurityRulesView listens
  }

  private void selectContext() {
    sec.setDomainContextObject(SecurityDialogFactory.getInstance().selectDomainContextObject(getStage(), getDomainContext()));
    secDomainContextObjectField.updateView();
    getContainer().getDelegate().fireViewToModelListeners();  // SecurityRulesView listens
  }


  private void updateEffectivePermissions() {
    // map to effective permissions
    Class[] permissions = SecurityFactory.getInstance().stringToPermissionInterfaces(sec.getPermissions());
    for (Map.Entry entry: permissionRadioButtons.entrySet()) {
      Permission permission = entry.getKey();
      FxRadioButton effectiveRadioButton = entry.getValue();
      if (sec.isAllowed()) {
        if (!effectiveRadioButton.getStyleClass().contains(ALLOW_STYLE)) {
          effectiveRadioButton.getStyleClass().add(ALLOW_STYLE);
        }
        effectiveRadioButton.getStyleClass().remove(DENY_STYLE);
        effectiveRadioButton.setSelected(
                permissions != null &&
                permission.appliesTo(clazz) &&
                permission.isAllowedBy(permissions));
      }
      else {
        if (!effectiveRadioButton.getStyleClass().contains(DENY_STYLE)) {
          effectiveRadioButton.getStyleClass().add(DENY_STYLE);
        }
        effectiveRadioButton.getStyleClass().remove(ALLOW_STYLE);
        effectiveRadioButton.setSelected(
                permissions != null &&
                permission.appliesTo(clazz) &&
                permission.isDeniedBy(permissions));
      }
    }
  }

  private void permissionsToModel() {
    Set permissions = new LinkedHashSet<>();
    for (Map.Entry entry: permissionCheckBoxes.entrySet()) {
      if (entry.getValue().isSelected()) {
        permissions.add(entry.getKey());
      }
    }
    sec.setPermissions(permissions.isEmpty() ? null : SecurityFactory.getInstance().permissionsToString(permissions));
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy