Page tree
Skip to end of metadata
Go to start of metadata

> The goal of this template is to remind you of many aspects that you could consider, to help you create a good concept. 
> Tip: Use whichever sections are appropriate for the concept, delete the rest, rename and add at will, these are simply a suggestion.
> Tip: Delete all these comments. 

Purpose

The Problem

Example Messages

Although messages are a platform thing the UI is heavily involved in displaying, dispatching and storing messages. It is clear that the UI framework should be concerned for the display and visualization of messages and notification but the UI should not be involved for dispatching and especially storing messages.

Here the call from the messages app as an example (apart from the Session all classes are part of ui-framework or message app):

MessagesViewImpl:sendButton → MessagesMainSubApp:handleGlobalMessage → AppInstanceControllerImpl:broadcastMessage → MessagesManagerImpl:broadcastMessage → :sendMessage → (MessageStore:saveMessage → Session.save() ; MessageManager:sendMessageSentEvent)

The reason is simple: Lets say we would like to develop a specific client for mobile devices (either a native app or a specific webapp) then we either had to depend on the vaadin based UI framework or reimplement everything for the other client which would lead to increased maintenance costs and failure rates.


Both MessageManager and MessageStore should be part of the core. Ideally what we dispatch to them is from the beginning a command to notify we want to send out messages. This will both hide JCR from the scene and make messages agnostic to the user may it be admin central, a special native app, a custom JavaScript admin interface, REST, ...


Example Resource Creation

What should happen if a resource is created or overloaded is configured in a UI action. This includes:

  • Finding the correct MediaType to set in the JCR properties
  • Set the correct metadata in JCR like size, extension, mimetype, etc
  • Set the modification date of this node

This functionality can't be reused by other systems other than admin central.


> AKA (Also known as): Starting Position
> Why is this concept being considered? What is the issue that someone is having that needs to be addressed? 

Goals

Separation

We aim to separate the the UI from backend operations and both have business logic code separated and are JCR agnostic in the frontend.

Reusability

Business logic like publication, uploading assets, change content (aka create new versions) or restore previous versions should be directly usable by many different users and not just admin central. REST endpoints is a good example or a new or specialized version of the UI.

Responsiveness

Asynchronous behavior, which commands aim for, should be baked into the core and therefore its easier on the front end to provide long running functionality.

Change centric vs node centric

Actions and commands should focus on the full context of a change and not just on one node. Actions become more scalable through this and its easier to apply an action on multiple nodes in one go.

Side effects

The following points are welcome side effects we try to achieve or automatically get but they don't have a main priority atm.

Testability

Through better separation both the business logic and frontend becomes easier to test and ideally many things we currently can only test with UI tests can be tested with just unit tests.


Use Cases

Admin Central

The action "Rename item" gathers the information which should change like: ID of the node to rename, new name, etc

    The action handler dispatches the appropriate command with this we leave the user and client context

        The central command handler will instantiate the correct command implementation and execute it

            The command will do the things it should do. In this case find the correct JCR node and set the new name. Fire events for the changed states.

        Command handler will make sure the events are forwarded to the correct users

    Action handler will propagate the changes to the data sources

Update on the data source will cause the UI to update (It would be ok or even advisable to already update the UI before: that means the error cases have to be handled more carefully!)


Proposal

Concept

Basically have the split of actions & commands like

Actions are the binding of front end specifics to a command. Actions together with the View Models () encapsulate the full lifecycle of data in the UI and handle both event dispatching and event handler for the data they are concerned. They do not implement business logic (at most they replicate or reuse it) and rely on the backend, through commands, on executing business logic.

Commands are user agnostic and can be used by an actual user interface like Admin Central or by a technical interface like REST or WebSockets. Commands encapsulate the steps behind state changes as well as side effects, like updating modification date or creating a new version, and communicating that changes to others.


Reasoning

> AKA: Rationale
> Pros and Cons
> Consequences of this approach. 

Implementation

Command Context

  • Calling User
  • Locale



With the use of completable future we could use the following pattern in the AddResourceAction e.g:


public class AddResourceAction extends AbstractAddResourceAction<AddResourceActionDefinition> {

    private final CommandBus cmdBus;

    @Inject
    public AddResourceAction(AddResourceActionDefinition definition, Item resourceItem, FormDialogPresenterFactory formDialogPresenterFactory, AppContext appContext, UiContext uiContext, ContentConnector contentConnector, SimpleTranslator i18n, LocationController locationController, ResourceOrigin origin, @Named(AdmincentralEventBus.NAME) EventBus eventBus, CommandBus cmdBus) {
        super(definition, resourceItem, formDialogPresenterFactory, appContext, uiContext, contentConnector, i18n, locationController, origin, eventBus);
        this.cmdBus = cmdBus;
    }

    /**
     * Adds a new resource to the {@link info.magnolia.resourceloader.jcr.JcrResourceOrigin}.
     *
     */
    @Override
    protected void addResource() {
        final AddResource newResource = contentConnector.createNewResourceCommand(getParentResource(), getNewResourceItem());

        this.cmdBus.dispatchCommand(newResource).thenAccept((e) -> {
            final DetailLocation detailLocation = new DetailLocation(appContext.getName(), HOTFIX_SUBAPP_NAME, DetailView.ViewType.ADD, newResource.getPath(), null);
            locationController.goTo(detailLocation);
        });

    }
}




Etcetera

> Possible Improvements

> Discarded Proposals

> Discussion

This is related to the following JIRA issues:

DEV-818 - Getting issue details... STATUS

DEV-856 - Getting issue details... STATUS

MGNLUI-3398 - Getting issue details... STATUS

This topic is related to some degree to CQRS. Here some links for interesting read-ups:



  • No labels