JMinor Application Framework

As simple as possible but not simpler

User Tools

Site Tools


documentation:tutorials:empdept

EmpDept: Application tutorial

Run the application

Web Start

EmpDept (Web Start)

You'll need to add http://jminor.no-ip.org to the Java exception site list.

Getdown

empdept-getdown.zip

Zip file containing the necessary files for running with Getdown.

Local JAR file

empdept-local.zip

Zip file containing a jar file along with an assortment of launch files for running the application without WebStart. Note that the remote configurations all assume the server is running on localhost.

Data

Domain model

We start by creating a class named EmpDept in a package of our choosing, we privatize the constructor and add a init() method, for loading this domain model. This first section also contains a few optional fields, which are included here for demonstration purposes, bundle and the i18n constants.

File: org/jminor/framework/demos/empdept/domain/EmpDept.java - lines #16-33

/**
 * This class contains the specification for the EmpDept application domain model
 */
public class EmpDept {
 
  private EmpDept() {}
  public static void init() {}
 
  private static final ResourceBundle bundle =
          ResourceBundle.getBundle("org.jminor.framework.demos.empdept.domain.EmpDept", Locale.getDefault());
 
  /**Used for i18n*/
  public static final String DEPARTMENT = "department";
  public static final String EMPLOYEE = "employee";
  public static final String NONE = "none";
  public static final String EMPLOYEE_REPORT = "employee_report";
  public static final String IMPORT_JSON = "import_json";

Next we define the constants required for the department entity, which is based on the DEPT table. One constant defines the entity itself and will be referred to as the entityID (here prefixed with T_), the other three represent the columns in the table and will be referred to as propertyIDs. The entityID in this example contains the actual table name (scott.dept), but the table name can be specified if that is preferred. The propertyIDs on the other hand do contain the actual column names from the table.

File: org/jminor/framework/demos/empdept/domain/EmpDept.java - lines #34-41

  /**Entity identifier for the table scott.dept*/
  public static final String T_DEPARTMENT = "scott.dept";
 
  /**Property identifiers for the columns in the scott.dept table*/
  public static final String DEPARTMENT_ID = "deptno";
  public static final String DEPARTMENT_NAME = "dname";
  public static final String DEPARTMENT_LOCATION = "loc";

Next we define the constants required for the employee entity, which is based on the EMP table. Here there are two additional propertyIDs with _FK suffixes, we'll use these later when we specify the foreign key properties for the employee entity.

File: org/jminor/framework/demos/empdept/domain/EmpDept.java - lines #42-60

  /**Entity identifier for the table scott.emp*/
  public static final String T_EMPLOYEE = "scott.emp";
 
  /**Property identifiers for the columns in the scott.emp table*/
  public static final String EMPLOYEE_ID = "empno";
  public static final String EMPLOYEE_NAME = "ename";
  public static final String EMPLOYEE_JOB = "job";
  public static final String EMPLOYEE_MGR = "mgr";
  public static final String EMPLOYEE_HIREDATE = "hiredate";
  public static final String EMPLOYEE_SALARY = "sal";
  public static final String EMPLOYEE_COMMISSION = "comm";
  public static final String EMPLOYEE_DEPARTMENT = "deptno";
  /**Foreign key (reference) identifier for the DEPT column in the table scott.emp*/
  public static final String EMPLOYEE_DEPARTMENT_FK = "dept_fk";
  /**Foreign key (reference) identifier for the MGR column in the table scott.emp*/
  public static final String EMPLOYEE_MGR_FK = "mgr_fk";
  /**Property identifier for the denormalized department location property*/
  public static final String EMPLOYEE_DEPARTMENT_LOCATION = "location";

In this section we define the department entity, by adding a EntityDefinition to the Entities repository. Since the entity definitions are inherently static and shared between application components, this is done within a static initializer block, which means that all you need to do to initialize the domain model is to call the init() method, in this case EmpDept.init().

EntityDefinition instances are provided by the Entities class, via the define method which comes in two flavours, one which assumes the entityID contains the underlying table name and one which does not, and therefore requires an additional tableName parameter. We use the latter below. Note that we fetch caption strings for the properties from the i18n bundle via getString(). In a single language model we would simply use “Caption” instead, see Chinook domain model. For an overview of the Property class see JMinor manual:Property. The EntityDefinition class provides chained setters for setting entity attributes, such as the primary key value source. Here we set idSource to IdSource.NONE since the department number is chosen manually, the so-called stringProvider which is responsible for providing toString() implementations for entities, the smallDataset attribute which hints that it is OK to automatically base ComboBoxes on the entity and we also set the caption. In this case we simply have the department string provider return the department name.

File: org/jminor/framework/demos/empdept/domain/EmpDept.java - lines #61-74

  static {
    /*Defining the entity type T_DEPARTMENT*/
    Entities.define(T_DEPARTMENT,
            Properties.primaryKeyProperty(DEPARTMENT_ID, Types.INTEGER, getString(DEPARTMENT_ID))
                    .setUpdatable(true).setNullable(false),
            Properties.columnProperty(DEPARTMENT_NAME, Types.VARCHAR, getString(DEPARTMENT_NAME))
                    .setPreferredColumnWidth(120).setMaxLength(14).setNullable(false),
            Properties.columnProperty(DEPARTMENT_LOCATION, Types.VARCHAR, getString(DEPARTMENT_LOCATION))
                    .setPreferredColumnWidth(150).setMaxLength(13))
            .setSmallDataset(true)
            .setOrderByClause(DEPARTMENT_NAME)
            .setStringProvider(new Entities.StringProvider(DEPARTMENT_NAME))
            .setCaption(getString(DEPARTMENT));

Next we define the employee entity. Here we set the keyGenerator to Entities.incrementKeyGenerator(T_EMPLOYEE, EMPLOYEE_ID) which, as the name suggests, simply increments the maximum column value by one (N.B. this is a very simplistic implementation which is absolutely not transaction safe). Here we also introduce the ForeignKeyProperty, the orderByClause, as well as a BackgroundColorProvider which is responsible for providing a custom color for a entity instance.

File: org/jminor/framework/demos/empdept/domain/EmpDept.java - lines #75-108

    /*Defining the entity type T_EMPLOYEE*/
    Entities.define(T_EMPLOYEE,
            Properties.primaryKeyProperty(EMPLOYEE_ID, Types.INTEGER, getString(EMPLOYEE_ID)),
            Properties.columnProperty(EMPLOYEE_NAME, Types.VARCHAR, getString(EMPLOYEE_NAME))
                    .setMaxLength(10).setNullable(false),
            Properties.foreignKeyProperty(EMPLOYEE_DEPARTMENT_FK, getString(EMPLOYEE_DEPARTMENT_FK), T_DEPARTMENT,
                    Properties.columnProperty(EMPLOYEE_DEPARTMENT))
                    .setNullable(false),
            Properties.valueListProperty(EMPLOYEE_JOB, Types.VARCHAR, getString(EMPLOYEE_JOB),
                    Arrays.asList(new Item("ANALYST"), new Item("CLERK"), new Item("MANAGER"), new Item("PRESIDENT"), new Item("SALESMAN"))),
            Properties.columnProperty(EMPLOYEE_SALARY, Types.DOUBLE, getString(EMPLOYEE_SALARY))
                    .setNullable(false).setMin(1000).setMax(10000).setMaximumFractionDigits(2),
            Properties.columnProperty(EMPLOYEE_COMMISSION, Types.DOUBLE, getString(EMPLOYEE_COMMISSION))
                    .setMin(100).setMax(2000).setMaximumFractionDigits(2),
            Properties.foreignKeyProperty(EMPLOYEE_MGR_FK, getString(EMPLOYEE_MGR_FK), T_EMPLOYEE,
                    Properties.columnProperty(EMPLOYEE_MGR)),
            Properties.columnProperty(EMPLOYEE_HIREDATE, Types.DATE, getString(EMPLOYEE_HIREDATE))
                    .setNullable(false),
            Properties.denormalizedViewProperty(EMPLOYEE_DEPARTMENT_LOCATION, EMPLOYEE_DEPARTMENT_FK,
                    Entities.getProperty(T_DEPARTMENT, DEPARTMENT_LOCATION),
                    getString(DEPARTMENT_LOCATION)).setPreferredColumnWidth(100))
            .setKeyGenerator(Entities.incrementKeyGenerator(T_EMPLOYEE, EMPLOYEE_ID))
            .setOrderByClause(EMPLOYEE_DEPARTMENT + ", " + EMPLOYEE_NAME)
            .setStringProvider(new Entities.StringProvider(EMPLOYEE_NAME))
            .setCaption(getString(EMPLOYEE))
            .setBackgroundColorProvider((entity, property) -> {
              if (property.is(EMPLOYEE_JOB) && "MANAGER".equals(entity.get(EMPLOYEE_JOB))) {
                return Color.CYAN;
              }
 
              return null;
            });
  }

At last there is the getString() method for retrieving i18n strings from the resource bundle.

File: org/jminor/framework/demos/empdept/domain/EmpDept.java - lines #109-113

  public static String getString(final String key) {
    return bundle.getString(key);
  }
}

Domain model unit test

Implementing the domain model unit test is a trivial thing, we extend EntityTestUnit and create a public test method for each entity we want tested and within that method call testEntity(ENTITY_ID). The EntityTestUnit relies on information from the domain model to construct random entity instances and run insert, update, select and delete tests. The tests are run within their own transactions which are then rolled back. We can provide our own entity instances if we'd like by overriding initializeTestEntity(String entityID) handling the cases we'd like and delegating the rest to the superclass implementation. The same can be done for referenced entities, that is, entities that are referenced via foreign keys and are required in order to be able to insert records.

File: org/jminor/framework/demos/empdept/domain/EmpDeptTest.java - lines #1-30

/*
 * Copyright (c) 2004 - 2017, Björn Darri Sigurðsson. All Rights Reserved.
 */
package org.jminor.framework.demos.empdept.domain;
 
import org.jminor.common.User;
import org.jminor.common.model.CancelException;
import org.jminor.framework.domain.testing.EntityTestUnit;
 
import org.junit.Test;
 
import static org.jminor.framework.demos.empdept.domain.EmpDept.T_DEPARTMENT;
import static org.jminor.framework.demos.empdept.domain.EmpDept.T_EMPLOYEE;
 
public class EmpDeptTest extends EntityTestUnit {
 
  private static final User UNIT_TEST_USER = new User(
          System.getProperty("jminor.unittest.username", "scott"),
          System.getProperty("jminor.unittest.password", "tiger"));
 
  @Test
  public void department() throws Exception {
    testEntity(T_DEPARTMENT);
  }
 
  @Test
  public void employee() throws Exception {
    testEntity(T_EMPLOYEE);
  }

We override getTestUser(), the default implementation simply prompts for login credentials.

File: org/jminor/framework/demos/empdept/domain/EmpDeptTest.java - lines #31-34

  @Override
  protected User getTestUser() throws CancelException {
    return UNIT_TEST_USER;

Here's another example:

  @Override
  protected User getTestUser() throws CancelException {
    return new User("scott", "tiger");
  }

And finally we implement loadDomainModel().

File: org/jminor/framework/demos/empdept/domain/EmpDeptTest.java - lines #36-40

  @Override
  protected void loadDomainModel() {
    EmpDept.init();
  }

Here are the parameters required for running the EmpDept test on the default H2 embedded database, assuming the database resides in the working directory.

-Djminor.db.type=h2

-Djminor.db.embedded=true

-Djminor.db.host=h2db/h2

For further information on parameters required for running JMinor applications see client configuration and server configuration.

Application model layer

In many cases we can use the default model implementations, but here we will customize the employee edit model by extending DefaultEntityEditModel.

We must provide a constructor taking a single EntityConnectionProvider parameter. We also call the bindEvents method we define later on.

File: org/jminor/framework/demos/empdept/beans/EmployeeEditModel.java - lines #22-26

  public EmployeeEditModel(final EntityConnectionProvider connectionProvider) {
    super(T_EMPLOYEE, connectionProvider);
    bindEvents();
  }

Now, at some point we are going to be editing the manager property of an employee which means we'll need a value list of managers. We override createForeignKeyComboBoxModel in order to provide a specialized combo box model for the manager property.

Note that the foreign key propertyID is used when referring to the manager property, very rarely do we have to worry about the underlying reference property.

After handling the manager case we simply delegate to the super class implementation, which by default creates an unfiltered EntityComboBoxModel, showing all the underlying entities.

File: org/jminor/framework/demos/empdept/beans/EmployeeEditModel.java - lines #27-43

  /** Providing a custom ComboBoxModel for the manager property, which only shows managers and the president */
  @Override
  public EntityComboBoxModel createForeignKeyComboBoxModel(final Property.ForeignKeyProperty foreignKeyProperty) {
    if (foreignKeyProperty.is(EMPLOYEE_MGR_FK)) {
      final EntityComboBoxModel managerModel = new SwingEntityComboBoxModel(T_EMPLOYEE, getConnectionProvider());
      managerModel.setNullValue(EntityUtil.createToStringEntity(T_EMPLOYEE, getString(NONE)));
      managerModel.setFilterSelectedItem(false);
      //Only show the president and managers
      managerModel.setSelectConditionProvider(() -> EntityConditions.propertyCondition(T_EMPLOYEE,
              EMPLOYEE_JOB, Condition.Type.LIKE, Arrays.asList("MANAGER", "PRESIDENT")));
 
      return managerModel;
    }
 
    return super.createForeignKeyComboBoxModel(foreignKeyProperty);
  }

Finally we bind a couple events, for further information see JMinor manual:Event binding.

File: org/jminor/framework/demos/empdept/beans/EmployeeEditModel.java - lines #44-63

  //keep event bindings in one place
  private void bindEvents() {
    //Refresh the manager ComboBoxModel when an employee is either added or updated
    addEntitiesChangedListener(() -> {
      if (containsComboBoxModel(EMPLOYEE_MGR_FK)) {
        getForeignKeyComboBoxModel(EMPLOYEE_MGR_FK).refresh();
      }
    });
    //Filter the manager ComboBoxModel so that only managers from the selected department are shown,
    //this filtering happens each time the department value is changed
    addValueListener(EMPLOYEE_DEPARTMENT_FK, info -> {
      //only show managers in the same department as the active entity
      if (containsComboBoxModel(EMPLOYEE_MGR_FK)) {
        getForeignKeyComboBoxModel(EMPLOYEE_MGR_FK).setFilterCondition(item -> Objects.equals(item.getForeignKey(EMPLOYEE_DEPARTMENT_FK), info.getNewValue())
                && !Objects.equals(item, getEntityCopy()));
      }
    });
  }
}

Application UI layer

If we want to do any editing we must provide a EntityEditPanel implementation for the entity, we start by creating a DepartmentEditPanel.

A class extending EntityEditPanel must provide a constructor taking a single EntityEditModel parameter.

File: org/jminor/framework/demos/empdept/beans/ui/DepartmentEditPanel.java - lines #17-22

  public DepartmentEditPanel(final SwingEntityEditModel editModel) {
    super(editModel);
  }

We override the intializeUI method to construct the actual UI, used for editing the department entity. The EntityEditPanel class provides methods for creating all the basic controls required, named create…, such as createTextField(propertyID) or createForeignKeyComboBox(foreignKeyPropertyID).

File: org/jminor/framework/demos/empdept/beans/ui/DepartmentEditPanel.java - lines #22-49

  @Override
  protected void initializeUI() {
    final JTextField txtDepartmentNumber = createTextField(DEPARTMENT_ID);
    UiUtil.makeUpperCase(createTextField(DEPARTMENT_NAME));
    UiUtil.makeUpperCase(createTextField(DEPARTMENT_LOCATION));
 
    setInitialFocusProperty(EmpDept.DEPARTMENT_ID);
    txtDepartmentNumber.setColumns(10);
 
    //we don't allow editing of the department number since it's a primary key
    getEditModel().getPrimaryKeyNullObserver().addListener(() -> {
      if (getEditModel().isEntityNew()) {
        txtDepartmentNumber.setEnabled(true);
        setInitialFocusProperty(EmpDept.DEPARTMENT_ID);
      }
      else {
        txtDepartmentNumber.setEnabled(false);
        setInitialFocusProperty(EmpDept.DEPARTMENT_NAME);
      }
    });
 
    setLayout(new GridLayout(3,1,5,5));
    addPropertyPanel(DEPARTMENT_ID);
    addPropertyPanel(DEPARTMENT_NAME);
    addPropertyPanel(DEPARTMENT_LOCATION);
  }
}

We extend EntityTablePanel for the department entity in order to provide a report print action.

A class extending EntityTablePanel must provide a constructor taking a single EntityTableModel parameter.

File: org/jminor/framework/demos/empdept/beans/ui/DepartmentTablePanel.java - lines #23-28

public class DepartmentTablePanel extends EntityTablePanel {
 
  public DepartmentTablePanel(final SwingEntityTableModel tableModel) {
    super(tableModel);
  }

We create a method for viewing a report, which is called via an action we'll initialize in the next step. For further information about report viewing and printing see JMinor manual:Reporting with JasperReports.

File: org/jminor/framework/demos/empdept/beans/ui/DepartmentTablePanel.java - lines #25-42

  public DepartmentTablePanel(final SwingEntityTableModel tableModel) {
    super(tableModel);
  }
 
  public void viewEmployeeReport() throws Exception {
    if (getEntityTableModel().getSelectionModel().isSelectionEmpty()) {
      return;
    }
 
    final String reportPath = EntityApplicationModel.getReportPath() + "/empdept_employees.jasper";
    final Collection departmentNumbers =
            EntityUtil.getDistinctValues(DEPARTMENT_ID, getEntityTableModel().getSelectionModel().getSelectedItems());
    final HashMap<String, Object> reportParameters = new HashMap<>();
    reportParameters.put("DEPTNO", departmentNumbers);
    EntityReportUiUtil.viewJdbcReport(DepartmentTablePanel.this, new JasperReportsWrapper(reportPath, reportParameters),
            new JasperReportsUIWrapper(), null, getEntityTableModel().getConnectionProvider());
  }

Next we override getPrintControls() to add our report action to the popup print control set.

File: org/jminor/framework/demos/empdept/beans/ui/DepartmentTablePanel.java - lines #43-51

  @Override
  protected ControlSet getPrintControls() {
    final ControlSet printControlSet = super.getPrintControls();
    printControlSet.add(Controls.control(this::viewEmployeeReport, EmpDept.getString(EMPLOYEE_REPORT)));
 
    return printControlSet;
  }
}

For editing employee entities we create the EmployeeEditPanel class.

File: org/jminor/framework/demos/empdept/beans/ui/EmployeeEditPanel.java - lines #17-22

public class EmployeeEditPanel extends EntityEditPanel {
 
  public EmployeeEditPanel(final SwingEntityEditModel editModel) {
    super(editModel);
  }

All we have to do is override initializeUI.

File: org/jminor/framework/demos/empdept/beans/ui/EmployeeEditPanel.java - lines #23-53

  @Override
  protected void initializeUI() {
    final JTextField txtName = (JTextField) UiUtil.makeUpperCase(createTextField(EMPLOYEE_NAME));
    createValueListComboBox(EMPLOYEE_JOB);
    final JComboBox boxManager = createForeignKeyComboBox(EMPLOYEE_MGR_FK);
    createForeignKeyComboBox(EMPLOYEE_DEPARTMENT_FK);
    createTextField(EMPLOYEE_SALARY);
    createTextField(EMPLOYEE_COMMISSION);
    createDateInputPanel(EMPLOYEE_HIREDATE, true);
 
    setInitialFocusComponent(txtName);
 
    txtName.setColumns(8);
    boxManager.setPreferredSize(UiUtil.getPreferredTextFieldSize());
 
    setLayout(new FlexibleGridLayout(3,3,5,5,true,false));
 
    addPropertyPanel(EMPLOYEE_NAME);
    addPropertyPanel(EMPLOYEE_JOB);
    addPropertyPanel(EMPLOYEE_DEPARTMENT_FK);
 
    addPropertyPanel(EMPLOYEE_MGR_FK);
    addPropertyPanel(EMPLOYEE_SALARY);
    addPropertyPanel(EMPLOYEE_COMMISSION);
 
    addPropertyPanel(EMPLOYEE_HIREDATE);
    add(new JLabel());
    add(new JLabel());
  }
}

Main application panel

We create a main application panel by extending EntityApplicationPanel. Overriding setupEntityPanelProviders() we configure two EntityPanelProvider objects, employeePanelProvider and departmentPanelProvider. We'll define the EmployeePanelProvider class later.

We override setupEntityPanelProviders and call addEntityPanelProvider() designating the department panel as the main application panel.

File: org/jminor/framework/demos/empdept/client/ui/EmpDeptAppPanel.java - lines #34-56

public class EmpDeptAppPanel extends EntityApplicationPanel<EmpDeptAppPanel.EmpDeptApplicationModel> {
 
  @Override
  protected void setupEntityPanelProviders() {
    final EmployeeModelProvider employeeModelProvider = new EmployeeModelProvider();
    final EmployeePanelProvider employeePanelProvider = new EmployeePanelProvider(employeeModelProvider);
    employeePanelProvider.setEditPanelClass(EmployeeEditPanel.class);
 
    final SwingEntityModelProvider departmentModelProvider = new SwingEntityModelProvider(T_DEPARTMENT) {
      @Override
      protected void configureModel(final SwingEntityModel entityModel) {
        entityModel.getDetailModel(EmpDept.T_EMPLOYEE).getTableModel().setQueryConditionRequired(false);
      }
    };
    departmentModelProvider.addDetailModelProvider(employeeModelProvider);
    final EntityPanelProvider departmentPanelProvider = new EntityPanelProvider(departmentModelProvider);
    departmentPanelProvider.setEditPanelClass(DepartmentEditPanel.class);
    departmentPanelProvider.setTablePanelClass(DepartmentTablePanel.class);
    departmentPanelProvider.addDetailPanelProvider(employeePanelProvider);
 
    addEntityPanelProvider(departmentPanelProvider);
  }

Next we add a method for importing a JSON text file, which we'll call via an action initialized in the next section.

File: org/jminor/framework/demos/empdept/client/ui/EmpDeptAppPanel.java - lines #57-62

  public void importJSON() throws Exception {
    final File file = UiUtil.selectFile(this, null);
    UiUtil.displayInDialog(this, EntityTablePanel.createStaticEntityTablePanel(EntityJSONParser.deserializeEntities(
            TextUtil.getTextFileContents(file.getAbsolutePath(), Charset.defaultCharset())), getModel().getConnectionProvider()), "Import");
  }

We override getToolsControlSet() to add our import action to the Tools menu.

File: org/jminor/framework/demos/empdept/client/ui/EmpDeptAppPanel.java - lines #63-70

  @Override
  protected ControlSet getToolsControlSet() {
    final ControlSet toolsSet = super.getToolsControlSet();
    toolsSet.add(Controls.control(this::importJSON, EmpDept.getString(IMPORT_JSON)));
 
    return toolsSet;
  }

We implement initializeApplicationModel() by returning an instance of the EmpDeptApplicationModel class, which we'll create later.

File: org/jminor/framework/demos/empdept/client/ui/EmpDeptAppPanel.java - lines #71-75

  @Override
  protected EmpDeptApplicationModel initializeApplicationModel(final EntityConnectionProvider connectionProvider) throws CancelException {
    return new EmpDeptApplicationModel(connectionProvider);
  }

We create a main() method for configuring and running the application.

File: org/jminor/framework/demos/empdept/client/ui/EmpDeptAppPanel.java - lines #76-82

  public static void main(final String[] args) {
    EntityPanel.TOOLBAR_BUTTONS.set(true);
    EntityPanel.COMPACT_ENTITY_PANEL_LAYOUT.set(true);
    new EmpDeptAppPanel().startApplication("Emp-Dept", null, false, UiUtil.getScreenSizeRatio(0.6), new User("scott", "tiger"));
  }

We then create the EmpDeptApplicationModel class by extending DefaultEntityApplicationModel.

File: org/jminor/framework/demos/empdept/client/ui/EmpDeptAppPanel.java - lines #83-93

    public EmpDeptApplicationModel(final EntityConnectionProvider connectionProvider) {
      super(connectionProvider);
    }
 
    @Override
    protected void loadDomainModel() {
      EmpDept.init();
    }
  }

We then create a EmployeeModelProvider by extending DefaultEntityModelProvider, in order to configure the table model after initialization.

File: org/jminor/framework/demos/empdept/client/ui/EmpDeptAppPanel.java - lines #94-105

    private EmployeeModelProvider() {
      super(EmpDept.T_EMPLOYEE);
      setEditModelClass(EmployeeEditModel.class);
    }
 
    @Override
    protected void configureTableModel(final SwingEntityTableModel tableModel) {
      tableModel.getColumnSummaryModel(EMPLOYEE_SALARY).setSummary(ColumnSummary.AVERAGE);
    }
  }

We create a EmployeePanelProvider by extending EntityPanelProvider, in order to configure the table panel after initialization.

File: org/jminor/framework/demos/empdept/client/ui/EmpDeptAppPanel.java - lines #106-117

    private EmployeePanelProvider(final EmployeeModelProvider modelProvider) {
      super(modelProvider);
    }
 
    @Override
    protected void configureTablePanel(final EntityTablePanel tablePanel) {
      tablePanel.setSummaryPanelVisible(true);
    }
  }
}

See client configuration for what is required for running the client.

Application load test

File: org/jminor/framework/demos/empdept/testing/EmpDeptLoadTest.java -

/*
 * Copyright (c) 2004 - 2017, Björn Darri Sigurðsson. All Rights Reserved.
 */
package org.jminor.framework.demos.empdept.testing;
 
import org.jminor.common.User;
import org.jminor.common.model.CancelException;
import org.jminor.framework.db.EntityConnectionProviders;
import org.jminor.framework.demos.empdept.client.ui.EmpDeptAppPanel;
import org.jminor.framework.demos.empdept.domain.EmpDept;
import org.jminor.framework.domain.Entity;
import org.jminor.framework.domain.testing.EntityTestUnit;
import org.jminor.framework.model.DefaultEntityApplicationModel;
import org.jminor.framework.model.EntityApplicationModel;
import org.jminor.framework.model.EntityLoadTestModel;
import org.jminor.framework.model.EntityModel;
import org.jminor.swing.common.ui.tools.LoadTestPanel;
import org.jminor.swing.framework.model.SwingEntityModel;
 
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
 
@SuppressWarnings({"UnusedDeclaration"})
public final class EmpDeptLoadTest extends EntityLoadTestModel {
 
  private static final User UNIT_TEST_USER = new User(
          System.getProperty("jminor.unittest.username", "scott"),
          System.getProperty("jminor.unittest.password", "tiger"));
 
  public EmpDeptLoadTest() {
    super(UNIT_TEST_USER, Arrays.asList(new InsertDepartment(), new InsertEmployee(), new LoginLogout(),
            new SelectDepartment(), new UpdateEmployee()));
  }
 
  @Override
  protected EntityApplicationModel initializeApplication() throws CancelException {
    final EntityApplicationModel applicationModel = new DefaultEntityApplicationModel(
            EntityConnectionProviders.connectionProvider(getUser(), EmpDeptLoadTest.class.getSimpleName())) {
      @Override
      protected void loadDomainModel() {
        EmpDept.init();
      }
    };
    final EntityModel deptModel = new SwingEntityModel(EmpDept.T_DEPARTMENT, applicationModel.getConnectionProvider());
    deptModel.addDetailModel(new SwingEntityModel(EmpDept.T_EMPLOYEE, applicationModel.getConnectionProvider()));
    applicationModel.addEntityModel(deptModel);
 
    final EntityModel model = applicationModel.getEntityModel(EmpDept.T_DEPARTMENT);
    model.addLinkedDetailModel(model.getDetailModel(EmpDept.T_EMPLOYEE));
    try {
      model.refresh();
    }
    catch (final Exception ignored) {/*ignored*/}
 
    return applicationModel;
  }
 
  private static final class SelectDepartment extends AbstractEntityUsageScenario<EmpDeptAppPanel.EmpDeptApplicationModel> {
    @Override
    protected void performScenario(final EmpDeptAppPanel.EmpDeptApplicationModel application) {
      selectRandomRow(application.getEntityModel(EmpDept.T_DEPARTMENT).getTableModel());
    }
    @Override
    public int getDefaultWeight() {
      return 10;
    }
  }
 
  private static final class UpdateEmployee extends AbstractEntityUsageScenario<EmpDeptAppPanel.EmpDeptApplicationModel> {
 
    private final Random random = new Random();
 
    @Override
    protected void performScenario(final EmpDeptAppPanel.EmpDeptApplicationModel application) throws ScenarioException {
      try {
        final SwingEntityModel departmentModel = application.getEntityModel(EmpDept.T_DEPARTMENT);
        selectRandomRow(departmentModel.getTableModel());
        final SwingEntityModel employeeModel = departmentModel.getDetailModel(EmpDept.T_EMPLOYEE);
        if (employeeModel.getTableModel().getRowCount() > 0) {
          employeeModel.getConnectionProvider().getConnection().beginTransaction();
          try {
            selectRandomRow(employeeModel.getTableModel());
            Entity selected = employeeModel.getTableModel().getSelectionModel().getSelectedItem();
            EntityTestUnit.randomize(selected, false, null);
            employeeModel.getEditModel().setEntity(selected);
            employeeModel.getEditModel().update();
            selectRandomRow(employeeModel.getTableModel());
            selected = employeeModel.getTableModel().getSelectionModel().getSelectedItem();
            EntityTestUnit.randomize(selected, false, null);
            employeeModel.getEditModel().setEntity(selected);
            employeeModel.getEditModel().update();
          }
          finally {
            if (random.nextDouble() < 0.5) {
              employeeModel.getConnectionProvider().getConnection().rollbackTransaction();
            }
            else {
              employeeModel.getConnectionProvider().getConnection().commitTransaction();
            }
          }
        }
      }
      catch (final Exception e) {
        throw new ScenarioException(e);
      }
    }
    @Override
    public int getDefaultWeight() {
      return 5;
    }
  }
 
  private static final class InsertEmployee extends AbstractEntityUsageScenario<EmpDeptAppPanel.EmpDeptApplicationModel> {
    @Override
    protected void performScenario(final EmpDeptAppPanel.EmpDeptApplicationModel application) throws ScenarioException {
      try {
        final SwingEntityModel departmentModel = application.getEntityModel(EmpDept.T_DEPARTMENT);
        selectRandomRow(departmentModel.getTableModel());
        final SwingEntityModel employeeModel = departmentModel.getDetailModel(EmpDept.T_EMPLOYEE);
        final Map<String, Entity> references = new HashMap<>();
        references.put(EmpDept.T_DEPARTMENT, departmentModel.getTableModel().getSelectionModel().getSelectedItem());
        employeeModel.getEditModel().setEntity(EntityTestUnit.createRandomEntity(EmpDept.T_EMPLOYEE, references));
        employeeModel.getEditModel().insert();
      }
      catch (final Exception e) {
        throw new ScenarioException(e);
      }
    }
    @Override
    public int getDefaultWeight() {
      return 3;
    }
  }
 
  private static final class InsertDepartment extends AbstractEntityUsageScenario<EmpDeptAppPanel.EmpDeptApplicationModel> {
    @Override
    protected void performScenario(final EmpDeptAppPanel.EmpDeptApplicationModel application) throws ScenarioException {
      try {
        final SwingEntityModel departmentModel = application.getEntityModel(EmpDept.T_DEPARTMENT);
        departmentModel.getEditModel().setEntity(EntityTestUnit.createRandomEntity(EmpDept.T_DEPARTMENT, null));
        departmentModel.getEditModel().insert();
      }
      catch (final Exception e) {
        throw new ScenarioException(e);
      }
    }
 
    @Override
    public int getDefaultWeight() {
      return 1;
    }
  }
 
  private static final class LoginLogout extends AbstractEntityUsageScenario<EmpDeptAppPanel.EmpDeptApplicationModel> {
    final Random random = new Random();
    @Override
    protected void performScenario(final EmpDeptAppPanel.EmpDeptApplicationModel application) {
      try {
        application.getConnectionProvider().disconnect();
        Thread.sleep(random.nextInt(1500));
        application.getConnectionProvider().getConnection();
      }
      catch (final InterruptedException ignored) {/*ignored*/}
    }
    @Override
    public int getDefaultWeight() {
      return 4;
    }
  }
 
  public static void main(final String[] args) throws Exception {
    SwingUtilities.invokeLater(new Runner());
  }
 
  private static final class Runner implements Runnable {
    @Override
    public void run() {
      try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        new LoadTestPanel(new EmpDeptLoadTest()).showFrame();
      }
      catch (final Exception e) {
        e.printStackTrace();
      }
    }
  }
}
documentation/tutorials/empdept.txt · Last modified: 2017/08/09 16:53 by darri