Thursday, 7 March 2013

JavaFx: Structuring your Application - Overview

Hi! I've given my blog a new home at http://www.yennicktrevels.com
You can find the new version of this post here: http://yennicktrevels.com/blog/2013/10/15/javafx-structuring-your-application-overview/

Introduction

JavaFx is a new rich client framework by Oracle. It allows you to create visually pleasing enterprise business applications with the Java language.

While many small demos are showing up in the community, there aren't many articles on how to structure your JavaFx application. Using a good structure makes it easier to maintain your application, add new features and improves overall stability. These are all very important in enterprise applications.
This serie of articles will try to remedy that by showing you one of many ways to structure your application. This is certainly not the only way to do it, but it will give you a starting point. Even this structure is open for improvement (as every structure is).

This serie will consist of four blog posts:
  1. Overview (this blog post)
  2. View layer
  3. Application logic layer
  4. Service - Application State layer

High-level Overview

The structure I will describe is based on Robotlegs, an Apache Flex micro-architecture library. But instead of using events to decouple the layers, I went with for direct calls (with interfaces in-between). While events allow you to decouple the layers even more, I prefer direct calls with interfaces over events because they make it easier to follow the flow of your application.

The diagram below shows the different components and layers in my architecture. The arrows indicate the dependencies.



  • View: This is where the JavaFx components are used to build the UI.
  • Mediator: The mediator facilitates the communication between the view and the application logic layer. This is why it's both included in the view layer as the application logic layer. This layer should not contain application logic, it's just a postman who receives calls from the view and delegates them to the application logic layer and vise versa.
  • Command: This is where your application logic will reside. A Command is a class which executes a single unit of work and will be disposed when it's finished.
  • Service: A service is used to access external resources. This can be a remote service, a file on the filesystem or a device attached to the user's pc.
  • Model: A model stores the state of your application. This can be the selected record which should be accessible in multiple views.

  • The diagram below shows a sample flow of an application. In this case the user clicked on a button to delete a contact in a list.



    1. The view asks the mediator to delete the item by calling the deleteContact(contact) method on the IContactListMediator interface.
    2. The mediator creates a new DeleteContactCommand and registers a success handler on it. Then it calls the start() method on the command.
    3. The command calls the contact service to delete the contact from the database
    4. The command calls a method on the model to remove the contact from the application state. It receives the updated list of contacts from the model
    5. The command finishes and triggers the registered success listeners. It provides the updated list of contacts to the success handlers.
    6. The success handler in the mediator asks the view to update the list of contacts based on the updated contact list it got from the command.

    Used libraries

    For my application I didn't use any framework (except for JavaFx, obviously), I wanted to create my own structure without the overhead of a framework. All I used was the JavaFx framework and Guice for dependency injection.
    For those interested in build tools, I used the JavaFx Gradle plugin created by Danno Ferrin to create a build script.

    Dependency Injection

    Mapping your dependencies

    A DI library like Guice allows you to inject instances of certain classes into other classes without you having to manually instantiate and inject them. This can greatly improve the quality of your code since you don't have to write all that yourself. Guice is basically the glue that holds your application together.

    In Guice you have to create a Module class which defines all the mappings. Such a module class can look like this for a simple application:
    public class EventManagerModule extends AbstractModule {
    
        @Override
        protected void configure() {
            bind(EventManagerModule.class).toInstance(this);
    
            mapViews();
            mapMediators();
            mapCommands();
            mapServices();
            mapModels();
            mapInfrastructure();
        }
    
        private void mapViews() {
            bind(IEventOverviewView.class).to(EventOverviewView.class);
            bind(IEventListView.class).to(EventListView.class);
            bind(IEventDetailView.class).to(EventDetailView.class);
        }
    
        private void mapMediators() {
            bind(IEventOverviewMediator.class).to(EventOverviewMediator.class);
            bind(IEventListMediator.class).to(EventListMediator.class);
            bind(IEventDetailMediator.class).to(EventDetailMediator.class);
        }
    
        private void mapCommands() {
            bind(ICommandProvider.class).to(CommandProvider);
    
            bind(LoadEventsCommand.class);
            bind(AcceptEventCommand.class);
            bind(DeclineEventCommand.class);
        }
    
        private void mapServices() {
            bind(IEventService.class).to(StubEventService.class);
        }
    
        private void mapModels() {
            bind(IEventSelectionModel.class).to(EventSelectionModel.class).in(Singleton.class);
        }
    
        private void mapInfrastructure() {
            bind(ITranslationProvider.class).to(ResourceBundleTranslationProvider.class).in(Singleton.class);
        }
    }
    
    So in most cases you will be mapping implementations to interfaces. Always try to use interfaces. This allows you to, for example, create a stub implementation of a service (in this case StubEventService) and a real implementation which you can then just swap by changing the Guice mapping.
    Only for the Commands I didn't create interfaces because they wouldn't add that much value. They would all practically be marker services, but you'll see that in my following posts.

    While this Module implementation is ok for a small application, it can quickly explode in one huge class when you're building a bigger application. This is where bootstrap classes come in handy. A bootstrap class is just a class which initializes a certain part of your application. In this case it would initialize the mappings of the views, the mediators or the commands. Such a bootstrap class would look like this:
    public class MediatorMapper implements Mapper {
    
        private AbstractModule module;
    
        public MediatorMapper(AbstractModule module) {
            this.module = module;
        }
    
        public void bootstrap() {
            module.bind(IEventOverviewMediator.class).to(EventOverviewMediator.class);
            module.bind(IEventListMediator.class).to(EventListMediator.class);
            module.bind(IEventDetailMediator.class).to(EventDetailMediator.class);
        }
    }
    
    Your module would then look like this:
    public class EventManagerModule extends AbstractModule {
    
        @Override
        protected void configure() {
            bind(EventManagerModule.class).toInstance(this)
    
            new ViewMapper(this).bootstrap();
            new MediatorMapper(this).bootstrap();
            new CommandMapper(this).bootstrap();
            new ServiceMapper(this).bootstrap();
            new ModelMapper(this).bootstrap();
            new ModelMapper(this).bootstrap();
        }
    }
    

    Wiring it all together

    Now how do you wire all this together? Well, that is what I'm going to show you now.

    In your Main class you will create a Guice Injector and with this injector you will instantiate the main view of your application. Your Main class will look like this:
    public class Main extends Application {
    
        public static void main(String[] args) {
            Application.launch();
        }
    
        @Override
        public void start(Stage stage) throws Exception {
            Injector injector = Guice.createInjector(new EventManagerModule());
            EventOverviewView eventOverviewView = injector.getInstance(EventOverviewView.class);
    
            Scene scene = SceneBuilder.create()
                    .root(
                        eventOverviewView.getView()
                    ).width(900)
                    .height(700)
                    .build();
            scene.getStylesheets().add(Main.class.getResource("/EventManager.css").toExternalForm());
    
            stage.setScene(scene);
            stage.show();
        }
    }
    
    The views that are being used in the main view are also injected in the main view. Also, the mediator that is behind the main view is also injected. This patterns is used for every view.
    public class EventOverviewView implements IEventOverviewView {
    
        @Inject
        public IEventOverviewMediator mediator;
        @Inject
        public EventListView eventListView;
        @Inject
        public EventDetailView eventDetailView;
    
        ...
    }
    
    Then, in the mediator, we inject the view and the commandProvider (this is a class which allows to create command instances on the fly).
    public class EventOverviewMediator implements IEventOverviewMediator {
    
        @Inject
        public IEventOverviewView view;
        @Inject
        public CommandProvider commandProvider;
    
        ...
    }
    
    And in the application logic layer we inject the service/model in the command.
    public class LoadEventsCommand extends Service<List<EventVO>> {
    
        @Inject
        public IEventService eventService;
    
        ...
    }
    

    Conclusion

    In this post I gave a broad overview of the structure and explained how dependency injection fits into this.
    In the following posts I will go into more detail for each layer and give some best practices.
    You can find the full sample application here: https://github.com/SlevinBE/JavaFx-structure-demo

    21 comments:

    1. Glad to see this. Cool approach too. Best practices for structuring JavaFX apps really haven't been established yet, so it is good to see some posts on the topic emerging.

      ReplyDelete
    2. The approach is too layered for my taste; I'd like to keep it simpel.

      Given that the view is defined in a FXML file (or setup manually), then the mediator would be a controller or backing bean. If the "delete contact" button is pressed, for me, the backing bean should do a (skipping null checks):

      em.find(Contact.class, 123).remove();

      And on success also remove the contract from the list in the backing bean populating the JavaFX ListView control (or maybe do a JPA query to repopulate).

      If you want to go enterpricy and move the whole business model onto its own application server, then the backing bean talks to that API directly. Say a REST interface:

      http[DELETE]://appserver/contact/123

      I'd drop the command layer completely.

      ReplyDelete
    3. If you would do all that in your backing bean then it can become a rather big class, which makes it harder to unit test (more dependencies, more code, ...).
      Also, you would have to make sure that in your backing bean all the logic/remote calls that can take some time are executed in a separate thread to not block the UI, which further clutters your code. In my approach this is nicely separated in the command layer.

      ReplyDelete
    4. We can KISS(Keep it simple , stupid) by making use of FXML - Controller class and simple methods that makes the CRUD operations.

      ReplyDelete
    5. Making sure the UI stays responsive is indeed the responsibility of the backing bean; it knows when it can simply wait or put stuff in a separate thread (and provide a feedback on progress). Of course some utility code to prevent scaffolding is needed, but it's all part of the UI layer. Naturally there should be no business logic in the backing bean, just the code connecting the UI to the model. Any business logic is part of the rich domain model.

      About the class growing; kinda depends on the JFX screen, but with loads of controls the backing bean can become bigger, yes. Hard to avoid. The per-control code still remains constrained to max 5 lines or so. On the other hand, a pile of interfaces don't make things more readable either.

      ReplyDelete
      Replies
      1. @tbee I think we both describe a valid architecture which can be used depending on the requirements of the application. Correct me if I'm wrong, but it looks like you are describing an architecture for a thin client (where the business logic is located on the server), while my architecture is for fat clients (business logic in the client).
        So in my case the client will be more complex (therefore the command layer), while your solution doesn't need that because the business logic is on the server.

        Delete
    6. I also thought about best practices for the structure of my JavaFX apps. I fully agree with Ajay V. that the use of FXML Controller classes is (in many cases) a good solution when separating application logic from actual UI elements.

      I created a small framework to ease the integration of Guice into your JavaFX applications a while ago (It's called: "fx-guice").

      --> https://github.com/cathive/fx-guice

      By extending "GuiceApplication" instead of "javafx.app.Application" you gain a bunch of advantages:
      * You can @Inject your app object anywhere as it will be
      automatically bound
      * You can use the GuiceFXMLLoader to load FXML files and use both
      @FXML and @Inject annotations in your FXML Controller classes
      * You can use @FxApplicatioNThread to mark methods that must be
      executed on the JavaFX event dispatch thread
      * ...

      "fx-guice" is published under the Apache License v2.

      Source code can be found on Github and ready-to-use artifacts can be found in the Sonatype OSS Maven repository. I also uploaded some (very simple) example apps (e.g. a cute little calculator) that shows how to use my framework.

      --> https://github.com/cathive/fx-guice/tree/master/examples/calculator-example-app


      I feel that writing the common boiler plate code over and over again is kind of boring and it's really time for a proper Guice extension to deal with JavaFX integration. :-)

      ReplyDelete
      Replies
      1. Cool! I'll certainly have a look at this. Something which nicely wires up FXML Controller classes with Guice was certainly missing up until now.

        Delete
    7. I'm looking for good information on IoC and presentation model, I hit a robot legs guy!

      I actually ran into Benjamin's library today ironically and am going to be using it in a couple of my desktop apps, it looks well written and has a lot of possibilities.

      I still have a ways to go to wrap my head around JavaFx, been into it 2 days now but, it looks very powerful for what I need.

      Funny enough and Apache Flex comitter, working on an AS3 -> JS cross compiler with Falcon.

      I will be reading your blog.

      PS I don't write any Flex code these days, but for some reason still love AS3.

      ReplyDelete
      Replies
      1. It's a small world ;)

        JavaFx is indeed very powerful (dare I say even more powerful than Flex). It has threads, the JVM languages (Java, Groovy, Scala,...), a build in Web engine (based on WebKit) and is imo architected better than Flex.

        I've been following the Apache Flex mailing list, and you're doing some great work on the AS3 -> JS part!

        Delete
    8. Yeah, just wait to see what is going to be released next week by Mike Laboriola and the gang. (IE Joel Hooks might might be floating around this project as well).

      Its something very fun with AS -> JS that you might actually think is quite interesting based on your interests of these types of design patterns.

      I have Caustic audio framework;

      http://www.teotigraphix.org/causticcore/overview/

      That is what I "do", writing a cross compiler is for run. :) So I am making desktop applications to manager mobile audio apps, JavaFX has really blown me away, I thought I was going to have to go back to 2002 and use Swing! :)

      Mike


      ReplyDelete
    9. I really like the way you structure the code. It's very clean, testable and easy to maintain. Besides the possibility of using some other posted libraries - I got a simple question.
      I've taken a look at the github repository - you're defining VOs (I guess View-Objects). How can this work together with persistent frameworks. I can't imagine any other possibility then converting the given VO to a POJO or direct sql - which both adds a lot of unnecessary code.

      What's your oppinion on this?

      ReplyDelete
      Replies
      1. The sample was made for a client-server architecture, so the client won't persist anything, that's the server's responsibility.
        So the server and client use VO objects to transfer data. The server will convert (e.g. Hibernate) mapped POJO's to VO and vise versa.
        This does indeed lead to a lot of extra code (in the form of mapper classes), but this is where mapper libraries like Dozer (http://dozer.sourceforge.net/documentation/gettingstarted.html) can help with.
        It also has a couple of important advantages:
        1. you can't get lazy initialization exceptions.
        2. The view only gets the information it needs and in the format it wants to use it.

        But if you have a simple application which needs to persist something to the database which doesn't necessarily requires a server, then feel free to replace those VO's with mapped POJO's and create a service in your client which persists these.

        So in the end it all depends on the type of application you want to build. For example this architecture is a fat client architecture, but if you want to keep your business logic on the server (thin client architecture) there may be better client architectures.

        Delete
    10. Hi,

      Thanx for the interesting post/topic (which is shamely rarely discussed by tutorials as you noticed).

      If I understand all of this correctly, your main entry point in the stack/structure of the application comes from the top (the view) :

      «
      Injector injector = Guice.createInjector(new EventManagerModule());
      EventOverviewView eventOverviewView = injector.getInstance(EventOverviewView.class);
      »

      Why doesnt the responsibility for entering the stack (initing the commands / creating the main view, etc.) doesnt come from the Mediator/Orchestrator/Controller/Whatever ?

      ReplyDelete
      Replies
      1. Because this was the most straightforward way to do it, I didn't want to make the initialization process more complex than it should be.
        If you look at it from a purely architectural/theoretical viewpoint you are indeed correct that this could be better initialized somewhere else. However, sometimes I weigh the cleanest solution to the amount of complexity it adds, and in this case I thought it wasn't worth it.

        Every JavaFx developer recognizes a Main class (or any class that has a main method and which extends Application) as the entry point of a JavaFx application. That's also why I do it in there because in most cases this class won't contain all that much code.

        Delete
    11. Awesome stuff, i used Robotlegs in tons of Projects and was looking for a similar aproach in JavaFX. Thats perfect. Not quite the same without the event dispatching stuff, but close.
      I also like building components in Flex better then JavaFX, but overall, its pretty much the same stuff.
      Still, love Flex and always will :D

      ReplyDelete
    12. Broken link to: structure-flow.png

      ReplyDelete
      Replies
      1. I can see the image and open it in a new tab (even after clearing my browser cache).

        Delete
    13. http://dl.bintray.com/content/shemnon/javafx-gradle/javafx.plugin asks for user+pass

      ReplyDelete
      Replies
      1. Fixed. I updated the url to the JavaFx gradle plugin in the build file.

        Delete
    14. It provide a simple but powerful pattern which will help you to structure your application.



      Thin Client Hardware & Zero Client

      ReplyDelete