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

org.tentackle.fx.rdc.security.SecurityRulesView 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 Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

package org.tentackle.fx.rdc.security;

import java.net.URL;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import org.tentackle.app.AbstractApplication;
import org.tentackle.bind.Bindable;
import org.tentackle.fx.AbstractFxController;
import org.tentackle.fx.Fx;
import org.tentackle.fx.FxControllerService;
import org.tentackle.fx.component.FxButton;
import org.tentackle.fx.component.FxTableView;
import org.tentackle.fx.container.FxTab;
import org.tentackle.fx.container.FxTabPane;
import org.tentackle.fx.container.FxVBox;
import org.tentackle.fx.rdc.RdcFactory;
import org.tentackle.fx.rdc.RdcFxRdcBundle;
import org.tentackle.fx.rdc.RdcRuntimeException;
import org.tentackle.fx.rdc.table.TablePopup;
import org.tentackle.misc.TrackedList;
import org.tentackle.pdo.DomainContext;
import org.tentackle.pdo.DomainContextProvider;
import org.tentackle.pdo.Pdo;
import org.tentackle.pdo.PdoUtilities;
import org.tentackle.pdo.PersistentDomainObject;
import org.tentackle.reflect.ReflectionHelper;
import org.tentackle.security.pdo.Security;
import org.tentackle.session.SessionUtilities;
import org.tentackle.validate.ValidationFailedException;

/**
 * CRUD controller for PDOs.
 *
 * @author harald
 */
@FxControllerService
public class SecurityRulesView extends AbstractFxController implements DomainContextProvider {

  /**
   * Creates and shows the modal stage.
   *
   * @param clazz the secured non-PDO class, null if PDO
   * @param pdo the secured PDO, null if non-PDO clazz
   */
  public static void show(Class clazz, PersistentDomainObject pdo) {
    Stage stage = Fx.createStage(Modality.APPLICATION_MODAL);
    SecurityRulesView controller = Fx.load(SecurityRulesView.class);
    if (pdo != null) {
      controller.setSecuredObject(pdo);
      stage.setTitle(MessageFormat.format(RdcFxRdcBundle.getString(
              "Security Rules for {0}"), pdo.getPlural()));
    }
    else {
      controller.setSecuredObject(clazz);
      stage.setTitle(MessageFormat.format(RdcFxRdcBundle.getString(
              "Security Rules for {0}"), ReflectionHelper.getClassBaseName(clazz)));
    }
    Scene scene = new Scene(controller.getView());
    stage.setScene(scene);
    stage.addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, e -> {
      if (controller.cancel()) {
        e.consume();
      }
    });
    stage.show();
  }

  @FXML
  private FxVBox vBox;
  @FXML
  private FxTabPane tabPane;
  @FXML
  private FxTab classTab;
  @FXML
  private FxTab pdoTab;
  @FXML
  private FxTableView classRulesNode;
  @FXML
  private FxTableView pdoRulesNode;

  @FXML
  private FxButton moveUpButton;
  @FXML
  private FxButton moveDownButton;
  @FXML
  private FxButton addButton;
  @FXML
  private FxButton removeButton;
  @FXML
  private FxButton saveButton;
  @FXML
  private FxButton cancelButton;

  @Bindable
  private ObservableList classRules;      // the security rules for the clazz
  private TrackedList trackedClassRules;  // to track the changes
  @Bindable
  private ObservableList pdoRules;        // the security rules for the PDO
  private TrackedList trackedPdoRules;    // to track the changes

  private ResourceBundle resources;                 // bundle
  private DomainContext context;                    // the domain context
  private PersistentDomainObject pdo;            // the PDO, null if application class
  private int classId;                              // the class id, 0 if non-PDO class
  private Class clazz;                           // the application class, null if PDO
  private SecurityEditor editor;                    // the editor for a rule
  private boolean withinSetupSecuredObject;         // true if selection changes must not trigger setRule

  @Override
  public DomainContext getDomainContext() {
    return context;
  }

  @Override
  public void initialize(URL location, ResourceBundle resources) {

    this.resources = resources;

    pdoRules = FXCollections.observableArrayList();
    classRules = FXCollections.observableArrayList();

    editor = Fx.load(SecurityEditor.class);
    editor.getContainer().addViewToModelListener(() -> Platform.runLater(() -> {
        classRulesNode.refresh();
        pdoRulesNode.refresh();
      })
    );
    vBox.getChildren().add(editor.getView());

    classRulesNode.getSelectionModel().selectedItemProperty().addListener((obs, ov, nv) -> setRule(nv));
    pdoRulesNode.getSelectionModel().selectedItemProperty().addListener((obs, ov, nv) -> setRule(nv));

    tabPane.getSelectionModel().selectedItemProperty().addListener((obs,ov,nv) -> {
      if (!withinSetupSecuredObject) {
        if (nv == classTab) {
          setRule(classRulesNode.getSelectionModel().getSelectedItem());
        }
        else if (nv == pdoTab) {
          setRule(pdoRulesNode.getSelectionModel().getSelectedItem());
        }
        else {
          setRule(null);
        }
      }
    });

    moveUpButton.setGraphic(Fx.createImageView("up"));
    moveUpButton.setOnAction(e -> moveUp());

    moveDownButton.setGraphic(Fx.createImageView("down"));
    moveDownButton.setOnAction(e -> moveDown());

    addButton.setGraphic(Fx.createImageView("add"));
    addButton.setOnAction(e -> add());

    removeButton.setGraphic(Fx.createImageView("delete"));
    removeButton.setOnAction(e -> remove());

    saveButton.setGraphic(Fx.createImageView("save"));
    saveButton.setOnAction(e -> save());

    cancelButton.setGraphic(Fx.createImageView("cancel"));
    cancelButton.setOnAction(e -> cancel());
  }


  @Override
  public void configure() {
    TablePopup classRulesPopup = RdcFactory.getInstance().createTablePopup(
            classRulesNode, "classRules", false, resources.getString("Class Rules"));
    classRulesPopup.loadPreferences();
    classRulesNode.setSortable(false);
    TablePopup pdoRulesPopup = RdcFactory.getInstance().createTablePopup(
            pdoRulesNode, "pdoRules", false, resources.getString("Object Rules"));
    pdoRulesPopup.loadPreferences();
    pdoRulesNode.setSortable(false);
  }


  /**
   * Configures the view to edit security rule sets for a PDO.
* * @param pdo the pdo */ public void setSecuredObject(PersistentDomainObject pdo) { this.pdo = pdo; classId = pdo.getClassId(); if (classId == 0) { throw new RdcRuntimeException(pdo.toGenericString() + " does not provide a class-ID"); } clazz = null; setupSecuredObject(); } /** * Configures the view to edit security rule sets for a PDO-class.
* * @param classId the class-ID */ public void setSecuredObject(int classId) { if (classId == 0) { throw new RdcRuntimeException("classId must be > 0"); } this.classId = classId; clazz = null; pdo = Pdo.create(SessionUtilities.getInstance().getClassName(classId), AbstractApplication.getRunningApplication().getDomainContext()); setupSecuredObject(); } /** * Configures the view to edit security rule sets for a non-PDO-class.
* * @param clazz the class */ public void setSecuredObject(Class clazz) { if (PersistentDomainObject.class.isAssignableFrom(clazz)) { throw new RdcRuntimeException(clazz + " is a persistent domain object"); } this.clazz = clazz; pdo = null; classId = 0; setupSecuredObject(); } /** * Sets up the securable object. */ private void setupSecuredObject() { withinSetupSecuredObject = true; if (pdo != null) { context = pdo.getDomainContext(); trackedClassRules = on(Security.class).selectByObject(classId, 0); classRules.setAll(trackedClassRules); classTab.setText(MessageFormat.format(RdcFxRdcBundle.getString( "Rules for all {0}"), pdo.getPlural())); if (pdo.isNew()) { trackedPdoRules = null; pdoRules.clear(); tabPane.getSelectionModel().select(classTab); tabPane.getTabs().remove(pdoTab); } else { trackedPdoRules = on(Security.class).selectByObject(classId, pdo.getId()); pdoRules.setAll(trackedPdoRules); tabPane.getSelectionModel().select(pdoTab); pdoTab.setText(MessageFormat.format(RdcFxRdcBundle.getString( "Rules for {0} {1}"), pdo.getSingular(), pdo.toString())); if (!tabPane.getTabs().contains(pdoTab)) { tabPane.getTabs().add(pdoTab); } } editor.setSecurableClass(pdo.getEffectiveClass()); } else { context = AbstractApplication.getRunningApplication().getDomainContext(); if (clazz != null) { trackedClassRules = on(Security.class).selectByObjectClass(clazz.getName()); classRules.setAll(trackedClassRules); classTab.setText(MessageFormat.format(RdcFxRdcBundle.getString( "Rules for {0}"), ReflectionHelper.getClassBaseName(clazz))); } else { classRules.clear(); trackedClassRules = null; classTab.setText(""); } pdoRules.clear(); trackedPdoRules = null; tabPane.getTabs().remove(pdoTab); tabPane.getSelectionModel().select(classTab); editor.setSecurableClass(clazz); } classRulesNode.getSelectionModel().clearSelection(); pdoRulesNode.getSelectionModel().clearSelection(); setRule(null); getContainer().updateView(); withinSetupSecuredObject = false; } /** * Sets the current rule. * * @param rule the rule, null if none */ private void setRule(Security rule) { if (rule == null) { editor.setPdo(on(Security.class)); editor.setChangeable(false); moveUpButton.setDisable(true); moveDownButton.setDisable(true); removeButton.setDisable(true); } else { editor.setPdo(rule); editor.setChangeable(true); int index = trackedClassRules.indexOf(rule); int size; if (index >= 0) { size = trackedClassRules.size(); } else { index = trackedPdoRules.indexOf(rule); size = trackedPdoRules.size(); } updateMoveButtons(index, size); removeButton.setDisable(false); } } private void updateMoveButtons(int index, int size) { moveUpButton.setDisable(index <= 0); moveDownButton.setDisable(index >= size - 1); } private void moveUp() { Security rule = editor.getPdo(); int index = trackedClassRules.indexOf(rule); if (index >= 0) { // cannot be 0, only to select the correct list trackedClassRules.remove(index); trackedClassRules.add(index - 1, rule); classRules.remove(index); classRules.add(index - 1, rule); classRulesNode.getSelectionModel().select(index - 1); } else { trackedPdoRules.remove(index); trackedPdoRules.add(index - 1, rule); pdoRules.remove(index); pdoRules.add(index - 1, rule); pdoRulesNode.getSelectionModel().select(index - 1); } } private void moveDown() { Security rule = editor.getPdo(); int index = trackedClassRules.indexOf(rule); if (index >= 0) { trackedClassRules.remove(index); trackedClassRules.add(index + 1, rule); classRules.remove(index); classRules.add(index + 1, rule); classRulesNode.getSelectionModel().select(index + 1); } else { trackedPdoRules.remove(index); trackedPdoRules.add(index + 1, rule); pdoRules.remove(index); pdoRules.add(index + 1, rule); pdoRulesNode.getSelectionModel().select(index + 1); } } private void add() { Security sec = on(Security.class); Tab tab = tabPane.getSelectionModel().getSelectedItem(); int ndx; if (tab == pdoTab) { ndx = pdoRulesNode.getSelectionModel().getSelectedIndex(); if (ndx == -1) { ndx = trackedPdoRules.size(); } trackedPdoRules.add(ndx, sec); pdoRules.add(ndx, sec); pdoRulesNode.getSelectionModel().select(ndx); } else { ndx = classRulesNode.getSelectionModel().getSelectedIndex(); if (ndx == -1) { ndx = trackedClassRules.size(); } trackedClassRules.add(ndx, sec); classRules.add(ndx, sec); classRulesNode.getSelectionModel().select(ndx); } } private void remove() { Security rule = editor.getPdo(); if (trackedClassRules.contains(rule)) { trackedClassRules.remove(rule); classRules.remove(rule); } else { trackedPdoRules.remove(rule); pdoRules.remove(rule); } } private void save() { // take a snapshot in case of rollback TrackedList trackedClassRulesSnapshot = trackedClassRules == null ? null : trackedClassRules.createSnapshot(); TrackedList trackedPdoRulesSnapshot = trackedPdoRules == null ? null : trackedPdoRules.createSnapshot(); try { getDomainContext().getSession().transaction(() -> { if (trackedClassRules != null) { PdoUtilities.getInstance().deleteCollection(trackedClassRules.getRemovedObjects()); int ndx = 0; for (Security sec: trackedClassRules) { sec.setPriority(ndx); if (classId != 0) { sec.setObjectClassId(classId); } else { sec.setObjectClassName(clazz.getName()); } ndx++; } PdoUtilities.getInstance().saveCollection(trackedClassRules); } if (trackedPdoRules != null) { PdoUtilities.getInstance().deleteCollection(trackedPdoRules.getRemovedObjects()); int ndx = 0; for (Security sec: trackedPdoRules) { sec.setPriority(ndx); sec.setObjectClassId(classId); sec.setObjectId(pdo.getId()); ndx++; } PdoUtilities.getInstance().saveCollection(trackedPdoRules); } return null; }); } catch (ValidationFailedException vx) { Fx.info(vx.resultsAsMessage()); if (trackedClassRulesSnapshot != null) { trackedClassRules.revertToSnapshot(trackedClassRulesSnapshot); classRules.setAll(trackedClassRules); } if (trackedPdoRulesSnapshot != null) { trackedPdoRules.revertToSnapshot(trackedPdoRulesSnapshot); pdoRules.setAll(trackedPdoRules); } return; } getStage().hide(); } private boolean cancel() { if ((trackedClassRules == null || !trackedClassRules.isModified() && !trackedClassRules.isElementModified()) && (trackedPdoRules == null || !trackedPdoRules.isModified() && !trackedPdoRules.isElementModified()) || Fx.question(RdcFxRdcBundle.getString("Rules were modified. Really discard all changes?"), false)) { getStage().hide(); return true; } return false; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy