4.5.1.3.4. AbstractEditor

AbstractEditor − базовый класс контроллеров экранов редактирования, является наследником AbstractWindow .

При создании конкретного класса контроллера рекомендуется параметризовать AbstractEditor типом редактируемой сущности. При этом методы getItem() и initItem() будут работать с конкретным типом сущности и прикладному коду не потребуется дополнительных приведений типов. Например:

public class CustomerEdit extends AbstractEditor<Customer> {

  @Override
  protected void initItem(Customer item) {
  ...

AbstractEditor определяет следующие собственные методы:

  • getItem() - возвращает экземпляр редактируемой сущности, установленный в главном источнике данных экрана (т.е. указанном в атрибуте datasource корневого элемента XML-дескриптора).

    Если редактируется не новый экземпляр, то в момент открытия экрана он перезагружается из базы данных с необходимым представлением, указанным для главного источника данных.

    Изменения, вносимые в экземпляр, возвращаемый getItem(), отражаются на состоянии источника данных, и будут отправлены на Middleware при коммите экрана.

    Следует иметь в виду, что getItem() возвращает значение только после инициализации экрана методом setItem(). До этого момента, например, в методах init() и initItem(), данный метод возвращает null.

    Однако в методе init() экземпляр сущности, переданный в openEditor(), можно получить из параметров следующим образом:

    @Override
    public void init(Map<String, Object> params) {
      Customer item = WindowParams.ITEM.getEntity(params);
      // do something
    }

    В метод initItem() экземпляр передается явно и нужного типа.

    В обоих случаях полученный экземпляр сущности, если он не новый, будет впоследствии перезагружен, и вносить в него изменения или сохранять в поле для последующего использования не имеет смысла.

  • setItem() - вызывается фреймворком при открытии экрана методом openEditor() для установки редактируемого экземпляра сущности в главном источнике данных. В момент вызова созданы все компоненты и источники данных экрана, и отработал метод init() контроллера.

    Для инициализации экрана редактирования вместо переопределения setItem() рекомендуется имплементировать специальные шаблонные методы initItem() и postInit().

  • initNewItem() - шаблонный метод, вызываемый фреймворком перед установкой редактируемого экземпляра сущности в главном источнике данных.

    Метод initNewItem() вызывается только для нового, только что созданного экземпляра сущности. Если редактируется detached экземпляр, метод не вызывается.

    Данный метод можно имплементировать в контроллере при необходимости инициализации нового экземпляра сущности перед его установкой в источник данных, например:

    @Inject
    private UserSession userSession;
    
    @Override
    protected void initNewItem(Complaint item) {
      item.setOpenedBy(userSession.getUser());
      item.setStatus(ComplaintStatus.OPENED);
    }

    Более сложный пример использования initNewItem() приведен в разделе рецептов разработки.

  • postInit() - шаблонный метод, вызываемый фреймворком сразу после установки редактируемого экземпляра сущности в главном источнике данных. Во время выполнения данного метода можно вызывать getItem(), который будет возвращать новый или перезагруженный при инициализации экрана экземпляр сущности.

    Данный метод можно имплементировать в контроллере для окончательной инициализации экрана, например:

    @Inject
    protected EntityDiffViewer diffFrame;
    
    @Override
    protected void postInit() {
      if (!PersistenceHelper.isNew(getItem())) {
          diffFrame.loadVersions(getItem());
      }
    }
  • commit() - валидировать экран и отправить изменения через DataSupplier на Middleware.

    Если используется вариант метода с параметром validate = false, то валидация перед коммитом не производится.

    Данный метод не рекомендуется переопределять, лучше использовать специальные шаблонные методы postValidate(), preCommit() и postCommit().

  • commitAndClose() - валидировать экран, отправить изменения на Middleware и закрыть экран. В метод preClose() и зарегистрированным слушателям CloseListener будет передано значение константы Window.COMMIT_ACTION_ID.

    Данный метод не рекомендуется переопределять, лучше использовать специальные шаблонные методы postValidate(), preCommit() и postCommit().

  • preCommit() - шаблонный метод, вызываемый фреймворком в процессе коммита изменений, после того как валидация завершена успешно и перед отправкой данных на Middleware.

    Данный метод можно имплементировать в контроллере. Если метод возвращает false, процесс коммита (и закрытия экрана, если был вызван commitAndClose()), прерывается. Например:

    @Override
    protected boolean preCommit() {
      if (somethingWentWrong) {
          showNotification("Something went wrong", NotificationType.WARNING);
          return false;
      }
      return true;
    }
  • postCommit() - шаблонный метод, вызываемый фреймворком на финальной стадии коммита изменений. Параметры метода:

    • committed - установлен в true, если в экране действительно были изменения, и они отправлены на Middleware;

    • close - установлен в true, если экран после коммита будет закрыт.

    Реализация метода по умолчанию, если экран не закрывается, отображает сообщение об успешном коммите изменений и вызывает метод postInit().

    Данный метод можно переопределить в контроллере для выполнения некоторых действий после успешного коммита, например:

    @Inject
    private Datasource<Driver> driverDs;
    @Inject
    private EntitySnapshotService entitySnapshotService;
    
    @Override
    protected boolean postCommit(boolean committed, boolean close) {
      if (committed) {
          entitySnapshotService.createSnapshot(driverDs.getItem(), driverDs.getView());
      }
      return super.postCommit(committed, close);
    }

Далее приведены диаграммы последовательностей инициализации и различных вариантов коммита экрана редактирования.

Рисунок 4.13. Инициализация экрана редактирования

Инициализация экрана редактирования

Рисунок 4.14. Коммит и закрытие экрана с фреймом editWindowActions

Коммит и закрытие экрана с фреймом editWindowActions

Рисунок 4.15. Коммит экрана с фреймом extendedEditWindowActions

Коммит экрана с фреймом extendedEditWindowActions

Рисунок 4.16. Коммит и закрытие экрана с фреймом extendedEditWindowActions

Коммит и закрытие экрана с фреймом extendedEditWindowActions