Architecture

JDance is built around a small set of concepts that are used consistently throughout an application.

The four most important parts are:

- Layout

- Panel

- Styling

- Actions

Layouts describe structure.

Panels add behavior around content.

Styling controls appearance, size and responsive behavior.

Actions connect the user interface to application behavior.

Together they form the basis of most JDance applications.

Layout

Layouts define how components are arranged.

A layout does not normally represent a feature by itself. Its responsibility is structure.

For example:

CODE
Page
    Header
    Body
        Sidebar
        Content
    Footer

This can be represented as nested layouts:

CODE
BasicLayout page = new BasicLayout(BasicLayout.Direction.VERTICAL);

page.add(header);
page.add(body);
page.add(footer);

The body can itself be another layout:

CODE
BasicLayout body = new BasicLayout(BasicLayout.Direction.HORIZONTAL);

body.add(sidebar);
body.add(content);

This is an important part of JDance architecture.

Large interfaces are not built as one large page definition. They are composed from smaller layouts containing other layouts and components.

BasicLayout

BasicLayout is the main general-purpose layout.

It can arrange its children vertically:

CODE
BasicLayout layout = new BasicLayout(BasicLayout.Direction.VERTICAL);

layout.add(title);
layout.add(content);
layout.add(buttons);

or horizontally:

CODE
BasicLayout layout = new BasicLayout(BasicLayout.Direction.HORIZONTAL);

layout.add(sidebar);
layout.add(content);

BasicLayout also controls properties such as sizing, padding, gap and alignment.

Specialized layouts

JDance also provides layouts for common structures.

CODE
VerticalLayout
    Components placed vertically

HorizontalLayout
    Components placed horizontally

GridLayout
    Components arranged in a grid

StackLayout
    Components placed in the same area

These exist so common structures do not need to be recreated manually.

The important concept is still the same: a layout controls composition and position.

Layout cells

When a component is added to a layout, the returned cell can control how that component behaves inside the layout.

For example:

CODE
BasicLayout layout = new BasicLayout(BasicLayout.Direction.HORIZONTAL);
layout.setRelativeWidth(100);

layout.add(sidebar).setRelativeWidth(25);
layout.add(content).setRelativeWidth(75);

The component describes what is rendered.

The layout cell describes how that component participates in the surrounding layout.

This keeps layout decisions outside the component itself when appropriate.

Panel

Panels wrap content and give it additional behavior.

A useful distinction is:

CODE
Layout
    Controls where content is placed

Panel
    Controls how content behaves

A panel normally contains another component.

CODE
Panel
    Component

The content itself does not need to implement the behavior provided by the panel.

LinkPanel

LinkPanel makes content interactive.

CODE
LinkPanel panel = new LinkPanel();
panel.setContent(content);

The content inside the panel can remain a normal component while the panel handles the interaction around it.

This is useful because visual structure and interaction behavior do not have to be implemented in the same class.

FormPanel

FormPanel represents form behavior.

Fields and buttons can be composed normally using layouts and then placed inside a FormPanel.

CODE
FormPanel
    Layout
        InputField
        InputField
        Button

The layout still controls structure.

The FormPanel provides the form behavior.

FixedPanel and StickyPanel

FixedPanel and StickyPanel change how content behaves relative to the browser viewport.

CODE
FixedPanel
    Content remains fixed

StickyPanel
    Content remains visible while scrolling

They can contain normal layouts and components.

This means viewport behavior can be added without changing the internal structure of the content.

WindowPanel

WindowPanel represents the outer browser window.

Most applications do not need to create a WindowPanel in every page.

Instead it is normally placed in a shared outer component such as MainFrame.

CODE
WindowPanel
    MainFrame
        Navbar
        Page content
        Footer

This gives the application one common outer structure.

Styling

Styling in JDance is part of the Java API.

Appearance, size, spacing, alignment and responsive behavior can all be configured directly on components and layouts.

There is normally no need for application code to manually construct CSS for common styling.

Appearance

Visual properties are represented by Java objects.

For example:

CODE
Text title = new Text("Account");

title.setFont(
    new Font()
        .setSize(22)
        .setBold(true)
        .setColor(new Color("#222222"))
);

Common styling objects include:

CODE
Font
Color
Border
Shadow

Size

Components and layout cells can use fixed or relative dimensions.

CODE
BasicLayout layout = new BasicLayout(BasicLayout.Direction.HORIZONTAL);
layout.setRelativeWidth(100);

layout.add(sidebar).setRelativeWidth(25);
layout.add(content).setRelativeWidth(75);

Sizing therefore becomes part of the component tree rather than a separate page definition.

Spacing

Padding and gaps are handled directly by layouts.

CODE
BasicLayout layout = new BasicLayout(BasicLayout.Direction.VERTICAL);

layout.setPadding(20);
layout.setGap(10);

Padding controls the inside of a layout.

Gap controls the distance between its cells.

Alignment

Layout cells control alignment.

CODE
layout.add(title).setHAlign(Align.CENTER);
layout.add(button).setHAlign(Align.RIGHT);

Horizontal and vertical alignment can be configured independently.

Responsive styling

JDance supports media-dependent properties.

A Media object describes a viewport range:

CODE
Media mobile = new Media(0,700);

Properties can then change for that media range.

CODE
BasicLayout layout = new BasicLayout(BasicLayout.Direction.HORIZONTAL);

layout.setDirection(
    mobile,
    BasicLayout.Direction.VERTICAL
);

The component tree remains the same.

Only the relevant properties change.

This means desktop and mobile versions normally do not require separate pages.

Skin

Larger applications commonly keep shared styling configuration in a Skin class.

A Skin can contain things such as:

CODE
Colors
Fonts
Text sizes
Heading sizes
Common Markit commands
Shared presentation settings

This keeps common visual decisions centralized.

For example, documentation headings, text and code blocks can all use the same shared configuration instead of defining their appearance separately on every page.

Actions

Actions connect the interface to behavior.

Layouts and panels describe the interface.

Styling controls how that interface looks.

Actions describe what happens when the application is used.

The main action types are:

CODE
HttpAction
AjaxAction
ServerAction

HttpAction

HttpAction handles normal HTTP requests.

It is the most commonly used action type.

A typical view action remains very small:

CODE
public class ViewAccount extends HttpAction{

    @Override
    public Component perform(HttpContext context) throws Exception{
        return new AccountPage();
    }

}

The action receives the request and decides what should be returned.

It should normally not contain the complete GUI itself.

View actions

Actions that display pages normally use the naming convention:

CODE
ViewHome
ViewAccount
ViewOrder
ViewSubscription

A class called ViewAccount therefore immediately communicates its responsibility.

It handles the request for viewing the account page.

AjaxAction

AjaxAction handles interaction with a page that is already open.

Typical uses include:

- Updating part of a page.

- Saving a field.

- Opening or closing interface elements.

- Refreshing content.

- Performing an operation without normal page navigation.

The interaction remains server-side while the existing browser interface can be updated.

ServerAction

ServerAction is used when the server needs to initiate an action toward an already connected browser.

This is commonly associated with WebSocket communication.

CODE
Server
    |
    v
ServerAction
    |
    v
Browser

HttpAction, AjaxAction and ServerAction therefore represent different forms of communication while using the same general action model.

Controllers

Controllers connect incoming communication to actions.

The main controller types are:

CODE
HttpController
AjaxController
WebsocketController

An application normally extends these with a small control class.

HttpControl

A typical HTTP controller looks like this:

CODE
@WebServlet(urlPatterns = {"/pub/*"},loadOnStartup = 1)
public class HttpControl extends HttpController{

    public static HttpControl instance;

    @Override
    public void init(){
        super.init();

        instance = this;

        getActionMapper().mapAction("/",ViewHome.class);
    }

}

HttpControl owns the HTTP action mapper for that web context.

The controller handles routing.

The individual HttpAction classes handle the requests.

AjaxControl

AjaxControl performs the same role for Ajax actions.

CODE
AjaxControl
    SaveAccount
    UpdateOrder
    RefreshContent

It extends JDance AjaxController and provides the action mapping used by Ajax actions.

WebsocketControl

WebsocketControl handles WebSocket communication.

It extends JDance WebsocketController and provides the connection used for server-side communication with the browser.

Contexts

Actions receive a context representing the current communication.

The main context types correspond to the controller and action types:

CODE
HttpContext
AjaxContext
WebsocketContext

For example:

CODE
public Component perform(HttpContext context) throws Exception{
    return new AccountPage();
}

The context provides the action with the JDance environment for the current request or connection.

This keeps the action API consistent without requiring application classes to manage the lower-level communication directly.

Pages

Pages are normally implemented as GuiComponent classes.

A page describes the larger GUI structure for one view.

For example:

CODE
public class AccountPage extends GuiComponent{

    @Override
    public void render(Writer out) throws Exception{
        BasicLayout layout = new BasicLayout(BasicLayout.Direction.VERTICAL);

        layout.add(new Text("Account"));
        layout.add(new AccountDetails());
        layout.add(new SubscriptionPanel());

        new MainFrame(layout)
                .setContext(context)
                .render(out);
    }

}

The page combines existing GUI parts.

It does not need to recreate every part of the application shell.

Reusable GUI

Repeated pieces of interface are normally implemented as GuiComponent classes.

Examples include:

CODE
Navbar
Footer
ProductCell
AccountHeader
UserMenu
SubscriptionPanel
SearchPanel

A reusable GUI class can internally use layouts, panels and ordinary components.

CODE
public class UserCard extends GuiComponent{

    private final User user;

    public UserCard(User user){
        this.user = user;
    }

    @Override
    public void render(Writer out) throws Exception{
        BasicLayout layout = new BasicLayout(BasicLayout.Direction.VERTICAL);

        layout.add(new Text(user.getName()));
        layout.add(new Button("Open"));

        layout.setContext(context).render(out);
    }

}

It can then be used like any other component:

CODE
layout.add(new UserCard(user));

This keeps pages focused on composition rather than implementation details.

MainFrame

MainFrame is normally the common outer structure of the web interface.

A typical MainFrame may contain:

CODE
WindowPanel
Navbar
Main content
Footer
Mobile navigation
Shared responsive structure

Individual pages provide the content.

MainFrame provides the common application frame.

CODE
WindowPanel
    MainFrame
        Navbar
        AccountPage
        Footer

This avoids repeating WindowPanel setup, navigation and common layout configuration in every page.

How the architecture fits together

A normal HTTP page request can be viewed like this:

CODE
Browser
    |
    v
HttpControl
    |
    v
ViewAccount
    |
    v
AccountPage
    |
    v
MainFrame
    |
    v
Layouts and Panels
    |
    v
Styled GUI
    |
    v
WindowPanel
    |
    v
Browser

Each layer has a different responsibility.

CODE
Layout
    Structures the interface

Panel
    Adds behavior around content

Styling
    Controls appearance and responsive behavior

Action
    Handles interaction

Controller
    Routes communication to actions

Context
    Represents the current communication

Page
    Composes the page-specific interface

MainFrame
    Provides the common application shell

The result is still one Java component tree rendered by JDance.

web/

A JDance application's web package is normally divided into contexts.

A common structure is:

CODE
web/
    adm/
    pub/
    usr/
    comps/

adm/ contains administration functionality.

pub/ contains public functionality.

usr/ contains functionality for logged-in users.

The top-level comps/ package contains GUI classes that are shared between contexts.

Web contexts

Each context normally contains:

CODE
pub/
    actions/
    comps/
    pages/

pages/ contains the larger page components.

comps/ contains reusable GUI used inside that context.

actions/ contains the interaction layer.

Action structure

Actions are normally divided by communication type:

CODE
actions/
    http/
    ajax/
    ws/

The controller for each type sits beside its actions.

CODE
actions/
    http/
        HttpControl.java
        ViewHome.java
        ViewAccount.java

    ajax/
        AjaxControl.java
        SaveAccount.java

    ws/
        WebsocketControl.java

The control class extends the corresponding JDance controller.

The other classes extend the corresponding JDance action type.

Pages and comps

The page structure might look like this:

CODE
pub/
    comps/
        ProductCell.java
        SearchPanel.java

    pages/
        HomePage.java
        ProductPage.java

Pages describe complete views.

Components contain reusable parts used by those pages.

Shared comps

Components shared by several contexts are commonly placed directly under web/comps/.

CODE
web/
    comps/
        MainFrame.java
        Navbar.java
        Footer.java
        Skin.java

These classes define the common outer structure and appearance of the application.

Complete web structure

A larger application may therefore look like this:

CODE
web/
    comps/
        MainFrame.java
        Navbar.java
        Footer.java
        Skin.java

    pub/
        actions/
            http/
                HttpControl.java
                ViewHome.java
                ViewProduct.java

            ajax/
                AjaxControl.java

            ws/
                WebsocketControl.java

        comps/
            ProductCell.java

        pages/
            HomePage.java
            ProductPage.java

    usr/
        actions/
            http/
            ajax/
            ws/

        comps/
        pages/

    adm/
        actions/
            http/
            ajax/
            ws/

        comps/
        pages/

The package structure mirrors the JDance architecture.

Controllers route.

Actions handle interaction.

Pages compose the interface.

Layouts structure it.

Panels add behavior.

Styling controls its presentation.

Shared GUI classes remove repetition.