Welcome to the Java Dance architecture

Table of Contents

What is Dance?

Pure Java web development.

Dance is an open source, very simple, yet powerful, component based architecture for developing web applications in pure Java.

As HTML, CSS and JavaScript development becomes increasingly complex, the idea is to boost productivity by creating a consistent API, manage complexity, and at the same time, bring all of Java’s features to front-end programming.

Features

This is in comparison to classic HTML/CSS/JavaScript development.

- Obviously, no cumbersome and time consuming HTML and CSS handcrafting.

- No messy mix of markup and Java code.

- Layout managers handle component layout.

- Seamless integration between front-end and back-end.

- Less room for human errors when HTML, CSS and JavaScript are automatically generated.

- Component based development.

- Easily extensible - if needed, making custom components is very straightforward.

- Readable and easy to understand front-end code.

- Less complex and much smaller code base.

- Much easier maintenance.

- Consistent code documentation.

- Most often, no need for testing in different browsers.

- Far better options when developing reusable code.

- Possibility to use encapsulation to manage complexity.

- More rapid prototyping and mockups.

- Common layouts that should be straightforward and intuitive to set up, now is.

- Much better error handling.

- Much less hard to find bugs and peculiarities.

- Easy for any Java developer to pick up front-end development.

- The web development team can focus on a single programming language.

- One language means better communication between front-end and back-end programmers.

- All features in modern advanced Java IDEs can be used in front-end programming.

- Inherently simple architecture that anyone with just some Java skills will understand.

- No need to load huge CSS or JavaScript libraries or plugins.

- Generated code is automatically minimized.

Contribute

We appreciate all kinds of comments and suggestions on how to improve the project. If you like to contribute code, you’re more then welcome. Please contact the maintainer.

Disclaimer

This software is distributed under the BSD 3-Clause License.

Requirements

A Java EE servlet 3.0 container server, like Tomcat, Jetty, GlassFish, JBoss, WebLogic, etc.

Installation

Just download the JavaDance04.jar file and add it to your class path.

Getting started

Hello world

We need two classes, a controller and an action. The controller maps a request to the action. For this example, the controller and it's actions need to be in the same package.

HttpControl.java

    import javax.servlet.annotation.WebServlet;
    import org.javadance.basic.http.HttpController;
    import org.javadance.basic.resources.Configurator;

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

        public static HttpControl instance;
        
        @Override
        public void init(){
            super.init();
            instance=this;
        }
    }

HelloWorldAction.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.http.*;

    public class HelloWorldAction extends HttpAction{
        
        @Override
        public void init(){
            setActionMapper(HttpControl.instance.getActionMapper());
        }

        @Override
        public GuiComponent perform(HttpContext context) throws Exception{
            return new Text("Hello, world!");
        }
    }

See the result

Fire up your favorite servlet container and enter this URL in the web browser

http://myhost/danceguide/helloWorldAction

where myhost may be something like localhost:8080 if you run locally, or your domain name if you run on a remote server.

Create a link

To make a link, we create a new action.

LinkAction.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.http.*;

    public class LinkAction extends HttpAction{

        @Override
        public void init(){
            setActionMapper(HttpControl.instance.getActionMapper());
        }
        
        @Override
        public GuiComponent perform(HttpContext context) throws Exception{

            LinkPanel linkPanel = new LinkPanel();
            linkPanel.setContent(new Text("Click to show Hello world"));
            linkPanel.onClick(new HelloWorldAction());

            return linkPanel;
        }
    }

See the result

http://myhost/danceguide/linkAction

LinkPanel is used to create a link to HelloWorldAction from previous example. Clickning the link will execute the HelloWorldAction.

Layout managers

To add components together, we use layout manages. They compose content and manage layout properties. Content can be any component, a text, link, or other layout managers. By combining layout manages, complex layouts can easily be achieved.

LayoutAction.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.http.*;

    public class LayoutAction extends HttpAction{

        @Override
        public void init(){
            setActionMapper(HttpControl.instance.getActionMapper());
        }
        
        @Override
        public GuiComponent perform(HttpContext context) throws Exception{
            
            HorizontalLayout hLayout = new HorizontalLayout();
            hLayout.setGap(10);
            hLayout.add(new Text("Left"));
            hLayout.add(new Text("Right"));
            
            VerticalLayout vLayout = new VerticalLayout();
            vLayout.setGap(10);
            vLayout.setPadding(10);
            vLayout.setBorder(new Border());
            vLayout.add(new Text("Top")).setHAlign(Align.CENTER);
            vLayout.add(hLayout);
            vLayout.add(new Text("Bottom")).setHAlign(Align.CENTER);

            return vLayout;
        }
    }

See the result

http://myhost/danceguide/layoutAction

Action parameters

This example shows how to send parameters with an action to the server. Clicking the button will execute the action itself and print the parameter value.

ParameterAction.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.http.*;

    public class ParameterAction extends HttpAction{

        @Override
        public void init(){
            setActionMapper(HttpControl.instance.getActionMapper());
        }
        
        @Override
        public GuiComponent perform(HttpContext context) throws Exception{
            
            //Get the parameter value
            String paramValue = context.getRequest().getParameter("paramName");
            
            //Create an action and add a parameter
            ParameterAction action = new ParameterAction();
            action.addParameter("paramName", "You clicked the action button");
            
            //Create a button to execute the action
            Button actionButton = new Button();
            actionButton.setText("Action »");
            actionButton.onClick(action);
            
            //Layout the component
            VerticalLayout layout = new VerticalLayout();
            layout.setPadding(10);
            layout.setGap(5);
            layout.add(actionButton);
            
            //If there is a parameter value, add it to the layout
            if(paramValue!=null){
                layout.add(new Text(paramValue));
            }
            
            //We always need the window panel
            WindowPanel windowPanel = new WindowPanel();
            windowPanel.setContent(layout);

            return windowPanel;
        }
    }

See the result

http://myhost/danceguide/parameterAction

A simple form

This example is similar to the previous one. It shows how to create and submit a form.

FormAction.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.http.*;

    public class FormAction extends HttpAction{

        @Override
        public void init(){
            setActionMapper(HttpControl.instance.getActionMapper());
        }
        
        @Override
        public GuiComponent perform(HttpContext context) throws Exception{
            
            //Get the parameter
            String paramValue = context.getRequest().getParameter("paramName");
                    
            //Create a text field
            InputField textField = new InputField();
            textField.setName("paramName");
            textField.setValue("You submitted the form");
            
            //Create a submit button
            Button submitButton = new Button();
            submitButton.setText("Submit");
            submitButton.onClick(new SubmitForm(new FormAction()));
            
            //Layout the components
            VerticalLayout layout = new VerticalLayout();
            layout.setPadding(10);
            layout.setGap(5);
            layout.add(textField);
            layout.add(submitButton).setHAlign(Align.RIGHT);
            
            //If there is a parameter value, add it to the layout
            if(paramValue!=null){
                layout.add(new Text(paramValue));
            }

            //This is a form, don't forget the form panel
            FormPanel formPanel = new FormPanel();
            formPanel.setContent(layout);
            
            //Window panel is always needed to render a document
            WindowPanel windowPanel = new WindowPanel();
            windowPanel.setContent(formPanel);

            return windowPanel;
        }
    }

See the result

http://myhost/danceguide/formAction

Responsive layout

We don’t really want any front-end code in the actions. That’s where the business logic should be. Instead, we create a page component and an action that views the page. This is a responsive three columns page. We keep using the same Controller.

ResponsivePage.java

    import java.io.Writer;
    import org.javadance.basic.gui.*;

    public class ResponsivePage extends GuiComponent{
        
        @Override
        public void render(Writer out) throws Exception{
            final Media MOBILE = new Media(0,600);

            Text menu = new Text("This might be a menu");
            Text content = new Text("This is some content");
            Text footer = new Text("Here goes the footer");

            Image image = new Image("http://danceguide.sparkney.com/256px-Two_dancers.jpg");
            image.setRelativeWidth(100);
            image.setTooltip("Dance image");
            
            BasicLayout layout = new BasicLayout(BasicLayout.Direction.HORIZONTAL);
            layout.setDirection(MOBILE, BasicLayout.Direction.VERTICAL);
            layout.setRelativeWidth(100);
            layout.setMaxWidth(800);
            layout.setPadding(10);
            layout.setCellPadding(10);
            layout.setGap(10).setGap(MOBILE,20);
            layout.setCellBorder(new Border());
            layout.add(content).setRelativeWidth(33).setRelativeWidth(MOBILE, 100);
            layout.add(image).setRelativeWidth(33).setRelativeWidth(MOBILE, 100);
            layout.add(menu).setRelativeWidth(33).setDisplay(MOBILE, false);
            
            BasicLayout centerLayout = new BasicLayout(BasicLayout.Direction.VERTICAL);
            centerLayout.setRelativeWidth(100);
            centerLayout.add(menu).setHAlign(Align.CENTER).setPadding(20).setDisplay(false).setDisplay(MOBILE, true);
            centerLayout.add(layout).setHAlign(Align.CENTER);
            centerLayout.add(footer).setHAlign(Align.CENTER).setPadding(40,0,40,0).setBackgroundColor(new Color("lightgray"));

            WindowPanel windowPanel = new WindowPanel();
            windowPanel.setContent(centerLayout);
            windowPanel.render(out);
            
        }
    }

Since actions do stuff, it’s a good idea to begin the name with a descriptive verb.

ViewResponsivePage.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.http.*;

    public class ViewResponsivePage extends HttpAction{
        
        @Override
        public void init(){
            setActionMapper(HttpControl.instance.getActionMapper());
        }

        @Override
        public GuiComponent perform(HttpContext context) throws Exception{
            return new ResponsivePage();
        }
    }

See the result

Execute the ViewComplexPage action and take a look at the result. Try changing browser width and see what happens.

http://myhost/danceguide/viewResponsivePage

Ajax actions

An ajax action is an asynchronous request that typically returns a component that updates an existing element on the page. An ajax action works a lot like standard actions, only we need to state what target element the result should end up in. To achieve this, we give the target element an ID, and we tell the ajax actions to put the result in the element by that ID.

First we create the ajax action. It extracts a message parameter, calculates the number of characters in the message, and returns the result as a component.

AjaxSubmit.java

    import org.javadance.basic.*;
    import org.javadance.basic.ajax.*;
    import org.javadance.basic.gui.*;

    public class AjaxSubmit extends AjaxAction{
        
        @Override
        public void init(){
            setActionMapper(AjaxControl.instance.getActionMapper());
        }

        @Override
        public PushAction perform(AjaxContext context) throws Exception{
            String message = context.getRequest().getParameter("message");

            String serverName = context.getRequest().getServerName();
            
            int lenght = message.length();
            
            Text resultText = new Text(serverName + " says message is "
                    + lenght + " characters long");
                    
            UpdateElement updateElement = new UpdateElement();
            updateElement.setElementId(AjaxPage.PANEL_ID);
            updateElement.setContent(resultText);
            
            return updateElement;
        }
        
    }

Then, we create a page containing a form, from which we can submit the ajax action. Note how we set the target element ID for the ajax action. We also create an empty layout cell and give it the same ID.

AjaxPage.java

    import java.io.Writer;
    import org.javadance.basic.gui.*;

    public class AjaxPage extends GuiComponent{
        public static final String PANEL_ID = "result";
        
        @Override
        public void render(Writer out) throws Exception{
            AjaxSubmit ajaxSubmit = new AjaxSubmit();
            
            InputField inputField = new InputField();
            inputField.setRelativeWidth(100);
            inputField.setName("message");
            inputField.onKeyUp(new SubmitForm(ajaxSubmit));
            
            VerticalLayout layout = new VerticalLayout();
            layout.setPadding(10);
            layout.setGap(5);
            layout.setWidth(200);
            layout.add(new Text("Enter a message"));
            layout.add(inputField);
            layout.add(new Space()).setId(PANEL_ID);
            
            FormPanel formPanel = new FormPanel();
            formPanel.setContent(layout);

            WindowPanel windowPanel = new WindowPanel();
            windowPanel.setContent(formPanel);
            windowPanel.render(out);
        }
    }

Finally, we create a standard action for viewing our ajax page.

ViewAjaxPage.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.http.*;

    public class ViewAjaxPage extends HttpAction{
        
        @Override
        public void init(){
            setActionMapper(HttpControl.instance.getActionMapper());
        }

        @Override
        public GuiComponent perform(HttpContext context) throws Exception{
            return new AjaxPage();
        }
    }

See the result

http://myhost/danceguide/viewAjaxPage

When you type in the text field, ajax requests are sent to the server. The server returns a component that is placed in the target element.

WebSocket

WebSockets are used for pushing data from the server to the client asynchronously.

WSControl.java

    import javax.websocket.server.ServerEndpoint;
    import org.javadance.basic.websocket.*;

    @ServerEndpoint(value="/wsdanceguide", configurator = WebsocketConfigurator.class)
    public class WSControl extends WebsocketController{
    }

WSSubmit.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.*;
    import org.javadance.basic.websocket.*;

    public class WSSubmit extends WebsocketAction{
        
        @Override
        public void perform(WebsocketContext context) throws Exception{
            String message = (String)getParameter("message");
            
            int lenght = message.length();
            
            Text resultText = new Text("Server says message is "
                    + lenght + " characters long");
                    
            UpdateElement updateElement = new UpdateElement();
            updateElement.setElementId(WSPage.PANEL_ID);
            updateElement.setContent(resultText);
            
            context.sendClientAction(updateElement);
        }
    }

WSPage.java

    import java.io.Writer;
    import org.javadance.basic.gui.*;

    public class WSPage extends GuiComponent{
        public static final String PANEL_ID = "result";
        
        @Override
        public void render(Writer out) throws Exception{
            WSControl wsc = new WSControl();
            WSControl.OpenStatement openStatement = wsc.getOpenStatement("localhost:8080", false);
            context.addOnLoad(openStatement);
                    
            WSSubmit wsSubmit = new WSSubmit();
            
            InputField inputField = new InputField();
            inputField.setRelativeWidth(100);
            inputField.setName("message");
            inputField.onKeyUp(new SubmitForm(wsSubmit));
            
            VerticalLayout layout = new VerticalLayout();
            layout.setPadding(10);
            layout.setGap(5);
            layout.setWidth(200);
            layout.add(new Text("Enter a message"));
            layout.add(inputField);
            layout.add(new Space()).setId(PANEL_ID);
            
            FormPanel formPanel = new FormPanel();
            formPanel.setContent(layout);

            WindowPanel windowPanel = new WindowPanel();
            windowPanel.setContent(formPanel);
            windowPanel.setContext(context).render(out);
        }
    }

ViewWSPage.java

    import org.javadance.basic.gui.*;
    import org.javadance.basic.http.*;

    public class ViewWSPage extends HttpAction{
        
        @Override
        public void init(){
            setActionMapper(HttpControl.instance.getActionMapper());
        }

        @Override
        public GuiComponent perform(HttpContext context) throws Exception{
            return new WSPage();
        }
    }

See the result

http://myhost/danceguide/viewWSPage

Brief history

The idea of Dance was borne back in 2001-2002, and originates in a lot of frustration with web development at the time. We wanted object oriented and component based tools for front-end. We got CSS. Layout managements became even worse than using tables.

I had been thinking of some sort of component based system for some time. We were already using Sun Microsystem MVC2 blueprint, but still had to deal with time consuming HTML/CSS.

Or even worse, we had do deal with subcontractors’ and non-programmers’ HTML/CSS. Often, those were art directors at advertising agencies that had become sort of web agencies. Their job was to maintain the HTML/CSS in frontend, so we were stuck with that. To solve this problem, we created a new project model that we called the WebManual. In short, it’s like an extended graphic manual defining all the graphic components in a web application. With the new project model, people who were experts in graphic design developed the WebManual, and we, who had some programming skills, implemented the WebManual in code, even the HTML/CSS. This worked out very well.

Now, we were not bound to HTML/CSS and we could start thinking out of the box. What finally sparked the idea of Dance was an article in Java Developer’s Journal, where a team, of some reason that I don’t remember, genereted some of the HTML/CSS code in a java object. Why not go all the way and let Java components generat all HTML/CSS code, add the components together like in Swing, and render them recursively?

A few days an nights later I had a working prototype. Since all controllers were rendered in a context and could be switched off, it even had decent modal dialogs, which was otherwise not possible at the time.

A few years later we did the first commercial project with Dance. Since then it has been improved over time, and we have had no trouble implementing new web technologies.

Ironically, since I maintain Dance, I have had to become an expert in HTML, CSS and JavaScript, technologies that I tried to get rid of. Maybe WebAssembly will save me in the future. :)

Contact

Maintainer
Örjan Derelöv
orjan@sparkney.se


Chef Contributor
Erik Derelöv