Welcome to jMDA

To generate software automatically has been a strong ambition since the early days of software development.

jMDA is a new approach in this area. It streamlines proven, widely known and accepted open source technologies into a most comprehensible and easy to use set of Java libraries that are extremely powerful and flexible at the same time. The main purpose of jMDA is

  • to leverage a comprehensible and easy to use modelling environment,

  • to provide convenient and complete access to modelling information and

  • to make available easy to use software generator facilities.

The introduction will briefly explain the main drivers behind this project, the jMDA book provides more detailed information about the most important concepts and the open source software is available here.

Sunday, 10 June 2018

javafx - combobox with autocompletion for custom types

Hi,

I'd like to share a solution for a javafx combobox with autocompletion for custom types. First of all I will show how to use it. Here is an example for a simple custom type that I will use for this example:

    private class Data implements Comparable<Data>
    {
        private String string;
        private Data(String string) { this.string = string; }
        @Override public int compareTo(Data o) { return string.compareTo(o.string); }
        @Override public String toString() { return string; }
    }

Next here comes an example for using autocompletion for the above custom type with the combobox:

        // create combo box (for custom type Data) as usual
        ComboBox<Data> cmbBx = new ComboBox<>();

        // cell factory that provides a list cell for a given Data item (see updateItem)
        Callback<ListView<Data>, ListCell<Data>> cellFactory =
                new Callback<ListView<Data>, ListCell<Data>>()
                {
                    @Override public ListCell<Data> call(ListView<Data> lv)
                    {
                        return new ListCell<Data>()
                        {
                            @Override protected void updateItem(Data item, boolean empty)
                            {
                                super.updateItem(item, empty);
                                if (item == null || empty) { setGraphic(null); }
                                else { setText(item.string); }
                            }
                        };
                    }
                };
        // converter that converts a given Data item to String and vice versa
        StringConverter<Data> converter =
                new StringConverter<Data>()
                {
                    @Override public String toString(Data item)
                    {
                        if (item == null) return null;
                        return item.string;
                    }

                    @Override public Data fromString(String string)
                    {
                        for (Data item : cmbBx.getItems())
                        {
                            if (item.string.equals(string)) return item;
                        }
                        return null;
                    }
                };

        // use the cell factory method to provide content for the button cell
        cmbBx.setButtonCell(cellFactory.call(null));
        // let the cell factory deliver the content of the cells
        cmbBx.setCellFactory(cellFactory);
        // set a condition that lets a Data item appear in the list of the auto complete suggestions or not
        Predicate<Data> predicate =
                data ->
                {
                    String cmbBxEditorTextToLowerCase = cmbBx.getEditor().getText().toLowerCase();
                    String dataStringToLowerCase = data.string.toLowerCase();
                    boolean result = dataStringToLowerCase.contains(cmbBxEditorTextToLowerCase);
                    return result;
                };

        cmbBx.setConverter(converter);

        // sample data
        ObservableList<Data> items = FXCollections.observableArrayList();
        items.add(new Data("apple1"));
        items.add(new Data("apple2"));
        items.add(new Data("apple3"));
        items.add(new Data("ball1"));
        items.add(new Data("ball2"));
        items.add(new Data("ball3"));
        items.add(new Data("cat1"));
        items.add(new Data("cat2"));
        items.add(new Data("cat3"));

        cmbBx.setItems(items);

The above preparations is pretty much conventional stuff that users of combo boxes have to deal with anyway in javafx.

However there is the predicate that should be mentioned here because it allows for "filtering" items of the combobox depending on the user input in the combo box editor. For the sample data above this means, that if the editor content is "a" all items are contained in the list of suggestions and if it is "t" then only the cats are contained.

To add this behaviour to combo boxes you simply do this:

        AutoCompleteComboBoxListener<Data> autoCompleteComboBoxListener =
                new AutoCompleteComboBoxListener<Data>(cmbBx, predicate);

One pretty little feature of AutoCompleteComboBoxListener is that you can change the items of the combo box on the fly by calling AutoCompleteComboBoxListener.repopulate(ObservableList<T> newPopulation).

So finally here is the code for AutoCompleteComboBoxListener:

import java.util.function.Predicate;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

public class AutoCompleteComboBoxListener<T> implements EventHandler<KeyEvent>
{
//    private final static Logger LOGGER = LogManager.getLogger(AutoCompleteComboBoxListener.class);

    // constructor injection
    private ComboBox<T> cmbBx;
    private Predicate<T> predicate;

    /** populated in constructor, holds a copy of the initial items */
    private ObservableList<T> initialItems = FXCollections.observableArrayList();

    public AutoCompleteComboBoxListener(final ComboBox<T> cmbBx, final Predicate<T> predicate)
    {
        this.cmbBx = cmbBx;
        this.predicate = predicate;

        initialItems.addAll(cmbBx.getItems());

        // if combobox was not editable all effort in this class would be superfluous
        cmbBx.setEditable(true);
        cmbBx.setOnAction
        (
                e ->
                {
                    cmbBx.getEditor().end();
//                    LOGGER.debug("editor: " + cmbBx.getEditor().getText() + ", value: " + cmbBx.getValue());
                }
        );
        cmbBx.setOnKeyReleased(this);
    }

    @Override public void handle(KeyEvent keyEvent)
    {
        // handle events that allow for early return
        if (keyEvent.getCode() == KeyCode.ENTER)
        {
            cmbBx.setValue(cmbBx.getSelectionModel().getSelectedItem());
//            LOGGER.debug("editor: " + cmbBx.getEditor().getText() + ", value: " + cmbBx.getValue());
            return;
        }
        if (keyEvent.getCode() == KeyCode.DOWN)
        {
            if (cmbBx.isShowing() == false)
            {
                cmbBx.show();
            }
            return;
        }
        if (   keyEvent.getCode() == KeyCode.LEFT
            || keyEvent.getCode() == KeyCode.RIGHT
            || keyEvent.getCode() == KeyCode.HOME
            || keyEvent.getCode() == KeyCode.END
            || keyEvent.getCode() == KeyCode.TAB
            || keyEvent.getCode() == KeyCode.BACK_SPACE
            || keyEvent.getCode() == KeyCode.DELETE
            || keyEvent.isControlDown()
            || keyEvent.isAltDown()
            || keyEvent.isShiftDown()
           )
        {
            return;
        }

        repopulate(initialItems);

        if (!cmbBx.getItems().isEmpty())
        {
            cmbBx.show();
        }
    }

    public void repopulate(ObservableList<T> newPopulation)
    {
        initialItems = newPopulation;

        boolean showing = cmbBx.isShowing();

        // combobox items will be repopulated, so make sure the "old" items do not show any longer on the
        // screen
        cmbBx.hide();

        // repopulate combobox.items with those initial items that match the predicate
        ObservableList<T> list = FXCollections.observableArrayList();
        cmbBx.setItems(list);

        initialItems
                .forEach
                (
                        item ->
                        {
                            if (predicate.test(item))
                            {
                                list.add(item);
                            }
                        }
                );

        if (showing) cmbBx.show();
    }
}

Cheers
Roger

Wednesday, 8 November 2017

jMDA still alive

Hi, jMDA offers some new and updated features. This is just a short teaser. If somebody finds this interesting please contact me. This might encourage me to provide better information about the details. In short: there is a tool that can be used to produce UML class diagram style representations from Java source and binary code. In addition there is plenty of code that helps to make
- code generation
- java annotation processing and
- access to package javax.lang.model stuff
extremely convenient. As for the class diagram tool, here is a screenshot that demonstrates what it can do:

alternative text
uml class diagram created from java types

Saturday, 5 October 2013

noDSL! – domain modelling with Java and software generation with jMDA

This article introduces many of the most important concepts of jMDA in a concise example. It demonstrates how domain modelling, domain model access and code generation can be covered in a single and very comprehensive Java source code file. jMDA offers all this in a straight forward manner: no proprietary DSL has to be defined, no IDE plugins are necessary.

Thursday, 26 September 2013

jump start annotation processing (even without annotations if you want)

With jmda.core you can easily perform annotation processing. What's more you can even do so if you do not have annotated code. Read this to find out how to do that.

define, compile and run dynamic code in RAM

jmda.core provides a feature that compiles and runs Java source code in RAM. Just define arbitrary executable Java source code in Strings, launch jmda RAMCompiler and execute the compiled output using standard Java reflection.

Friday, 20 September 2013

Monday, 24 June 2013

annotation processing rounds explained

There is a new article describing how javac controls annotation processing rounds here.

jump start annotation processing within minutes using jMDA tasks

jMDA introduces annotation processing tasks to facilitate jsr 269 utilisation. You can find a short introduction in how to use annotation processing tasks here.

Sunday, 16 June 2013

jMDA publishes jMDA book 1.0.0 together with new versions of jmda.core and jmda.sample

The new book is work in progress and will contain the most recent information available about jMDA products in the future. You can download version 1.0.0 here.

Sunday, 5 May 2013

jMDA releases version 1.0.0 of its software modelling and generator framework


Today jMDA released a major upgrade of it's software modelling and generator framework. This article is an excerpt of a larger document describing jMDA that will be published later.

Sunday, 30 December 2012

sample: jboss 7 datasource definition with derby network client

I've been messing around with JBoss 7 and Apache Derby Network Client lately. I did not find a datasource configuration example for exactly this combination so I post this to spare others annoying investigations on this.

To sum it up: The configuration for my simple environment is very straight forward, especially there is no need to define a JBoss module or to specify particular Derby JDBC driver classes. All you have to do is place derbyclient.jar into JBoss deployments directory and insert a datasource definition into the respective section of the JBoss standalone.xml as follows:

<datasources>
  ...
  <datasource jndi-name="java:/DataSourceDerbyNetwork"

              pool-name="DataSourceDerbyNetwork">
    <connection-url>jdbc:derby://localhost:1527/c:/data/db/derby/xxx;create=true</connection-url>
    <driver>derbyclient.jar</driver>
    <pool>
      <min-pool-size>5</min-pool-size>
      <max-pool-size>20</max-pool-size>
    </pool>
    <security>
      <user-name>yyy</user-name>
      <password>zzz</password>
    </security>
    <timeout>
      <idle-timeout-minutes>5</idle-timeout-minutes>
    </timeout>
    <statement>
      <track-statements>true</track-statements>
    </statement>
  </datasource>

  ...
</datasources>


Of course you have to adjust the data printed in bold according to your individual needs. Please refer to the Derby documentation for further details about the connection-url for example.

By the way: I removed the default datasource ExampleDS from standalone.xml and did not observe this causing any problems. Seems that ExampleDS, as its name says, is used for examples only.

Sunday, 7 October 2012

Avoid unnecessary qualified type references in generated source code

The new version of jmda.gen provides convenient and smart support for Java code generators to produce exactly those import statements that were needed. It also helps to avoid unnecessary qualified type names in generated code as well as name collisions in generated import statements.

Monday, 17 September 2012

Combine jmda.core with jmda.gen and create JUnit test suites for existing JUnit tests

This new example demonstrates how to combine the jmda.core and jmda.gen libraries. It shows how to find all JUnit test methods in a code base and and how to create JUnit test suites that automatically run all JUnit tests package by package.

Saturday, 8 September 2012

Create a simple Java source code generator with four lines of code using jmda.gen

I wrote a small quickstart example of how to get started with the jmda.gen framework. Hope you find this interesting.

Complete redesign of jmda.gen generator framework

During the recent months I redesigned the jmda.gen generator framework completely. Today I start publishing previews of the upcoming new version 0.9 because I think that the library becomes more and more stable and mature. So if you are interested in building your own generators in a really comfortable and flexible manner then try and check out what jmda.gen can offer. You can find a jmda.gen quickstart example here.

Friday, 22 June 2012

Create / update jaxb.index files

Creating or Updating jaxb.index files with jMDA JAXB sample tools is as easy as this:


    Map<File, Set<String>> indexData =
        JAXBIndexDataBuilder.build(rootDirectory);
    
    for (File packageDirectory : indexData.keySet())
    {
      FileUtils.writeLines(
          new File(packageDirectory, "jaxb.index"),
          indexData.get(packageDirectory));
    }
The updated the .zip file contains the JAXBIndexFileWriter class which does pretty much the same as what is shown above.

Saturday, 16 June 2012

New jMDA based tools help to keep JAXB index files and package lists in sync

A new "getting started" example has just been published. It describes how jMDA makes it extremely easy to develope tools that help to accomplish some tedious maintainance tasks when working with JAXB. The tools use information provided by a simple jMDA processor.

Update of jmda.core available

A new version of jmda.core (jmda.core-0.8.1) is available. For a summary of new features and improvements see release-notes.txt inside the downloadable zip archive.

Sunday, 3 June 2012

What has been going on with jMDA in the recent year?

When I discussed about jMDA with colleagues and friends in the past it became obvious that one thing is missing. Textual models such as Java source code files in jMDA are fine but graphical models often are sooo muuuch mooore expressive!

I could not disagree with that and because I'm a huge UML fan I started looking around for appropriate Java to UML reverse engineering tools. It soon turned out that it was not easy to find any. Existing products often are extreme heavy weights, clumsy to use, expensive and so on. So I started playing around with an own solution. With jMDA at hand I had everything necessary to find out anything about a given jMDA model so the only thing to do was to bring that model information into an appealing graphical representation. First results looked very promising (at least in my eyes).

But soon some really nasty problems occured. The biggest among them being myself and my lacking knowledge and experience in developing software with a huge amount of obviously non mainstream graphical requirements. I started with a Java Swing approach but got frustrated about a lot of features that seem to be missing.

Then I decided to try JavaFX 2.0. Again first results looked promising but missing basic features were a big disappointment.

After all I spent a lot of time in these investigations during the last year without satisfying results. However recently I became to know UML Explorer which does most of the things I was looking for very nicely in an eclipse environment. So I gave up or at least postponed my plans for an own solution. This will allow to concentrate on developing new and improving existing features for the actual jMDA products.

Saturday, 2 June 2012

New blog started for jMDA

More than one and a half year after publishing jMDA as an open source project I start this blog today. The blog is meant to provide up to date information about hopefully interesting things related to jMDA. It will replace the old project home page which will be discontinued soon.
With this blog I hope to increase community interest and participation in jMDA and would be happy to receive comments and feedback. In the jMDA project I'd like to collaboratively improve and extend jMDA technology. I plan to discuss and publish new libraries that address particular application fields for jMDA.
Finally this blog wants to be a place for the community to share ideas and discuss jMDA related topics.
Some initial information about jMDA is already available here.