GMapsFX 2.0.5 Released

GMapsFX 2.0.5 has been released and is now available via bintray and maven central.

This version contains a major bugfix where the directions pane was always enabled.  The framework has been updated to make the direction pane an option that can be toggled on or off at runtime as it is needed.

GMapsFX is a Java library that makes it extremely easy to add a Google Map to a JavaFX application.

 

<dependency> 
  <groupId>com.lynden</groupId> 
  <artifactId>GMapsFX</artifactId> 
  <version>2.0.5</version> 
  <type>pom</type> 
</dependency>

 

GMaps Home: http://rterp.github.io/GMapsFX/
twitter: @RobTerpilowski

Advertisements

JavaFX vs. Swing vs. HTML5, Who Wins? – My Interview with Alexander Casall

In November 2015 Dirk Lemmermann (Freelancer) and Alexander Casall of Saxonia Systems had a JavaOne session about JavaFX Real World Applications. The article 20 JavaFX real-world applications summarizes the presentation by showing the applications that they’ve talked about. In addition to providing example applications for the article, I was interviewed by Alexander to get my thoughts on JavaFX and desktop development in general. The interview appears below.

Can you tell us about the highlights when you used JavaFX?

The animated transitions and effects such as blurring or drop shadows make a huge difference in the user experience of the application when implemented properly. These are small details that sometimes get glossed over, but when introduced to an application can create a very polished UI.  The effects and transitions were something that were possible to do with Swing, but it was so painful.  I don’t remember how many times I had to override the paintComponent() method to customize the look of a particular component, but all of this is baked into the JavaFX framework, allowing you to do these things in literally a few lines of code.

What is your general opinion about JavaFX?

Overall I am pleased with JavaFX as a successor to Swing.  The addition of property bindings, which eliminate the need for event listeners in many circumstances helps cut down on some of the code complexity.  I also like the fact that there is a very clear seperation between the model, view, and controller, where the view is FXML, the model can be a collection of JavaFX properties, and the controller utilizes dependency injection to have the UI components passed in.  There are some nice tools for doing JavaFX development, including NetBeans for coding, SceneBuilder as a WYSIWYG design tool and ScenicView to help visual provide information about the application while it is running.

JavaFX, Swing, SWT, HTML5 – Who wins – or better, when to use what?

For a new application I would not consider Swing or SWT, which leaves either JavaFX or HTML5 as the remaining options.  In this case there is not a clear winner, but a set of tradeoffs one needs to consider when making a decision.  With HTML5 you have the advantage of being able to deploy your application across many different platforms (phones, tablets, and Desktops), as well as multiple OSs (Windows, Mac, Linux).  There is also the benefit of a huge development community and large selection of open source tools and frameworks.  The ease of deployment across platforms comes at a cost however, in that you must operate within the constraints that are placed on you by the browser. The amount of time debugging issues across different browsers or OSs is often overlooked or underestimated by teams when deciding whether or not to go the desktop or web app route.  We recently worked on a project where a very large chunk of time had been consumed in order to get a piece of functionality working correctly in IE 9 on Windows.With JavaFX the drawback is that the user has to download and install something to their desktop, which is becoming very old fashioned.  But if this is not an issue, then you are free to develop outside the constraints of the browser and use the full power of the Java language and the eco system that backs it.For applications that are used internally within the company I feel that it makes a lot of sense to deploy these at desktop applications for this reason.  Deployments are not an issue in this case as we can automatically push out new installations or updates to PCs in our network automatically.  We also bundle a private JRE with the application so we don’t need to worry about which version(s) of Java the user has installed on their PC.

How satisfied are you with the work of Oracle on JavaFX?

Jonathan Giles and his team have been doing great work at Oracle adding improving and enhancing the JavaFX libraries.  That being said, it would be nice if Oracle officially stated what their long term plans are with JavaFX.  When Oracle let go of some of their evangelists (who were big proponents of JavaFX), just before JavaOne it started a rumor mill of what may have been behind the move.  The uncertainty this has created, and lack of official communication from Oracle will likely deter some development teams who may be on the fence about whether they should port legacy Swing application to JavaFX or HTML5. Over time this will potentially affect how large the JavaFX community eventually becomes.

What do you miss in the work with JavaFX?

The amount of 3rd party component libraries (both open source and commercial) that are available for JavaFX is still somewhat limited at this point, but that should change as the JavaFX community continues to grow.

 

twitter: @RobTerpilowski
LinkedIn: Rob Terpilowski

Version 1.1.2 of JavaFxPropertyHelper NetBeans Plugin Released

This a minor release of the JavaFxPropertyHelper NetBeans plugin, and will now follow JavaFX best practices by marking any get/set methods as final.

 

This plugin would create the following methods:

public final String getName() {
    return name.get();
}

public final void setName( String value ) {
    name.set(value);
}

public final StringProperty nameProperty() {
    return name;
}

 

The latest release version can either be download from github:
Or the NetBeans plug-in portal page.

Handy Tools for JavaFX Development

If you are building an application with JavaFx there are a few tools that will make your life a whole lot easier and save you a lot of time.


Scene Builder

The WYSIWYG drag-n-drop design tool for JavaFx will build an FXML representation of the UI which can then be loaded by a JavaFx application.  Scene Builder helps to enforce the MVC pattern, keeping business logic out of the code that describes the UI. (More on this below).

SceneBuilder1

Scene builder also has a nice “CSS Analyzer” feature which will show you the full CSS path to a component that is selected in the tool.  This has come in handy when attempting to figure out what the CSS path for a component is when attempting to determine where to apply a CSS style .  I wish I had known about this when I first began using JavaFx, as it was previously a trial-and-error process for me to get a component styled correctly.

SceneBuilder2

Gluon, Inc. has taken over the build and release of the Scene Builder installer packages which can be obtained at the following link: http://gluonhq.com/open-source/scene-builder/


NetBeans

Of course you will need a good IDE for developing the remaining, and NetBeans provides a number of features which helps out with developing with JavaFX.

The first is the autocomplete feature when working with the FXML files that are generated by Scene Builder.  The IDE will generate a list of possible values when inserting or modifying nodes.

NetbeansFx

There is also support when working with the JavaFX CSS files that will be loaded by the application.  In the example below, NetBeans generates a list of possible colors for the -fx-background-color property.

NetbeansFxCss

Finally, there is a code generator plugin which will generate getter and setter methods for JavaFX properties in a POJO class.  The normal Getter/Setter functionality would return a StringProperty object for the name variable (below), when ideally I would want the class me to return the actual String that the property represents.  A screen shot below shows the “Generate” popup menu item with the “JavaFx Props Getters & Setters”.  Once selected, the following screenshot illustrates the code that is generated.

The plugin is available at the link below.

https://github.com/rterp/JavaFxPropertyHelperNBPlugin/releases/download/1.0.0/JavaFxPropertyHelperNBPlugin-1.0.0.nbm

Ubuntu1

NetbeansFx2


Scenic View

Scenic View is another helpful tool when developing and debugging JavaFX applications.  It is a stand alone GUI application which will attach to a JavaFX application, and display all the nodes in the scene graph in a collapsable tree.  On the right side of the UI it will display various properties about the selected node.  ie min height, max height, location, css styles, etc.  In the screenshot below Scenic View is in front on the right side of the screen, and the application being debugged is behind Scenic View on the left side of the screen.  The selected button on the app is highlighted yellow, and Scenic View has selected this button in its tree view and is displaying its properties in the table on the right.

Scenic View can be downloaded at the FxExperience website.

ScenicView


MvvMFxLogo

Finally, MvvmFX is a framework for implementing the Model-View-ViewModel (MVVM) pattern in JavaFX.  This pattern allows you to separate any business logic related to the UI from the UI data and state, meaning that the business logic behind the UI can be unit tested without creating any UI components.  Since the view model doesn’t know about the view, it makes it possible to replace the view without requiring modifications to the view model.

An instance of the view model is injected into the view, which is just a JavaFx controller for a component.  An example view/controller class is shown below.

NetbeansFxMvvM

twitter: @RobTerpilowski
LinkedIn: Profile

MVC tutorial with the NetBeans Rich Client Platform (RCP) and JavaFX

This tutorial illustrates the creation of a small application based on the NetBeans Rich Client Platform (RCP), and JavaFx, which will monitor the prices of a few stocks and update the UI in real time as prices are updated.  The application will make use of SceneBuilder to create an main UI, and JavaFX property bindings in order to keep the UI up to date as the prices are updated.


The Model

First, lets start with the model, a Stock class which will simply consist of a ticker symbol and a name.

public class Stock {
    
    protected String symbol;
    protected String name;

    public Stock(String symbol, String name) {
        this.symbol = symbol;
        this.name = name;
    }

    public String getSymbol() {
        return symbol;
    }

    public String getName() {
        return name;
    }    
}

Next, the listener interface that we will need to implement in order to get updates on the prices.  The priceUpdated() method will be invoked whenever a new price arrives for a stock.


public interface StockPriceUpdatedListener {

    public void priceUpdated( Stock stock, double price );
    
}

The model will consist of a collection of stocks, each of which will be mapped to a StringProperty.  When a new stock is added to the model, a new StringProperty will be created and mapped to the specified stock.  The model implements the StockPriceUpdatedListener interface.  When a new price is received, the StringProperty for that Stock will be looked up and updated.

Note that in the model below that you need to be on the main JavaFx thread when you update a property!  For the purposes of this application the stock prices are arriving from a non-ui thread, so updating the property needs to be wrapped in a Platform.runLater() call which will put the update on to the ui-thread.


import com.mvc.stock.price.Stock;
import com.mvc.stock.price.StockPriceUpdatedListener;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class StockModel implements StockPriceUpdatedListener {
    
    protected Map<Stock, StringProperty> stocks = new HashMap<>();
    DecimalFormat df = new DecimalFormat("$##0.00");
    
    public StringProperty addStock( Stock stock ) {
        StringProperty property = stocks.get(stock);
        if( property == null ) {
            property = new SimpleStringProperty("");
            stocks.put(stock, property);
        }
        
        return property;
    }
    
    @Override
    public void priceUpdated(Stock stock, double price) {
        //Don't update the properties from a non-JavaFx-UI thread!
        Platform.runLater( () -> stocks.get(stock).setValue(df.format(price)));
    }    
}


The View

Next, the view for this application was designed with SceneBuilder.  The layout consists of a GridPane containing information about a few stocks, as well as a subscribe button which will trigger the monitoring of price information.

Screen Shot 2015-06-12 at 1.06.11 PM

SceneBuilder generated the following FXML code below, with the UI controller set to:

com.mvc.stock.ui.StockPriceController

Also note that the button has its onAction event defined to call the subscribeButtonClicked() method which will need to be implemented in the StockPriceController class.


<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>


<AnchorPane id="AnchorPane" prefHeight="197.0" prefWidth="233.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="com.mvc.stock.ui.StockPricePanelController">
    <children>
        <GridPane alignment="CENTER" gridLinesVisible="true" layoutX="14.0" layoutY="14.0">
            <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
            </columnConstraints>
            <rowConstraints>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
            </rowConstraints>
            <children>
                <Label text="MSFT" GridPane.halignment="RIGHT" GridPane.rowIndex="1">
                    <padding>
                        <Insets right="10.0" />
                    </padding>
                </Label>
                <Label alignment="CENTER" text="Stock" textAlignment="CENTER" GridPane.halignment="CENTER">
                    <padding>
                        <Insets right="10.0" />
                    </padding>
                    <font>
                        <Font name="System Bold" size="13.0" />
                    </font>
                </Label>
                <Label text="Last Price" GridPane.columnIndex="1" GridPane.halignment="CENTER">
                    <font>
                        <Font name="System Bold" size="13.0" />
                    </font>
                </Label>
                <Label text="EBAY" GridPane.halignment="RIGHT" GridPane.rowIndex="3">
                    <padding>
                        <Insets right="10.0" />
                    </padding>
                </Label>
                <Label text="AMZN" GridPane.halignment="RIGHT" GridPane.rowIndex="2">
                    <padding>
                        <Insets right="10.0" />
                    </padding>
                </Label>
                <Label fx:id="msftPriceLabel" GridPane.columnIndex="1" GridPane.rowIndex="1">
                    <padding>
                        <Insets left="10.0" />
                    </padding>
                </Label>
                <Label fx:id="amznPriceLabel" GridPane.columnIndex="1" GridPane.rowIndex="2">
                    <padding>
                        <Insets left="10.0" />
                    </padding>
                </Label>
                <Label fx:id="ebayPriceLabel" GridPane.columnIndex="1" GridPane.rowIndex="3">
                    <padding>
                        <Insets left="10.0" />
                    </padding>
                </Label>
            </children>
        </GridPane>
        <Button fx:id="subscribeButton" layoutX="136.0" layoutY="153.0" mnemonicParsing="false" onAction="#subscribeButtonClicked" text="Subscribe" />
    </children>
</AnchorPane>



The Controller

As mentioned above, the FXML file references StockPricePanelController as the UI’s controller.  The controller has 3 labels and a button defined which will be injected into the controller by annotating those fields with the @FXML annotation.  When the controller is first initialized it creates a new stock object for each stock and then binds the StringProperty of the StockModel to the StringProperty of its corresponding label.

Also, as previously stated, the controller will need to implement a method called subscribeButtonClicked() which was defined in the FXML above.  This method needs to be annotated with the @FXML annotation in order to be invoked when the subscribeButton is clicked.  When this action is invoked, the controller will subscribe to price data for the specified stocks.


import com.mvc.stock.price.Stock;
import com.mvc.stock.price.provider.IStockPriceProvider;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

/**
 * FXML Controller class
 *
 */
public class StockPricePanelController implements Initializable {

    
    @FXML
    protected Label msftPriceLabel;
    
    @FXML
    protected Label amznPriceLabel;
    
    @FXML
    protected Label ebayPriceLabel;
    
    @FXML
    protected Button subscribeButton;
    
    protected StockModel stockModel;
    
    protected IStockPriceProvider provider;
    protected Stock msft = new Stock("MSFT", "Microsoft");
    protected Stock amzn = new Stock("AMZN", "Amazon");
    protected Stock ebay = new Stock("EBAY", "eBay");
    
    
    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        stockModel = new StockModel();
        //bind the string property from the model to the labels.
        msftPriceLabel.textProperty().bindBidirectional( stockModel.addStock(msft) );
        amznPriceLabel.textProperty().bindBidirectional( stockModel.addStock(amzn) );
        ebayPriceLabel.textProperty().bindBidirectional( stockModel.addStock(ebay) );
    }    

    public IStockPriceProvider getProvider() {
        return provider;
    }

    public void setProvider(IStockPriceProvider provider) {
        this.provider = provider;
    }

    @FXML
    public void subscribeButtonClicked( ActionEvent event ) {
        if( provider != null ) {
            provider.subscribeToPriceData(msft, stockModel);
            provider.subscribeToPriceData(amzn, stockModel);
            provider.subscribeToPriceData(ebay, stockModel);
        }
    }
    
}

The final piece is to tie JavaFX UI into the NetBeans module which this component is a part of.  In order to do this you will need to have a TopComponent defined for your module like in the example below.  Basically a TopComponent is a top level panel that is usually within a TabbedPane in the main UI.  The TopComponent class below uses the Lookup API to find an implementation of an IStockPriceProvider interface.  Next a JFXPanel is created, which is a Swing JPanel that can hold a JavaFX Scene.

Within the Platform.runLater() method, a new FXMLLoader is created which points to the location of the FXML file from above.  Once the loader has loaded the file, we can obtain a reference to the StockPricePanelController, and pass in the instance of the stockPriceProvider that was previously just looked up.

Finally, a new Scene is created,  added to the JFXPanel, and the JFXPanel is added to the Center position of the TopComponent.


public final class StockPriceTopComponent extends TopComponent {

    public StockPriceTopComponent() {
        initComponents();
        setName(Bundle.CTL_StockPriceTopComponent());
        setToolTipText(Bundle.HINT_StockPriceTopComponent());
        putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE);
        putClientProperty(TopComponent.PROP_DRAGGING_DISABLED, Boolean.TRUE);
        putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE);
        
        
        IStockPriceProvider stockPriceProvider = Lookup.getDefault().lookup(IStockPriceProvider.class);
        if( stockPriceProvider == null ) {
            throw new IllegalStateException( "Provider is null");
        }        
        
        JFXPanel jfxPanel = new JFXPanel();

        //This needs to be set to make sure the JavaFx thread doesn't exit if the tab is closed.
        Platform.setImplicitExit(false);
        
        // create JavaFX scene
        Platform.runLater(() -> {
            Parent root;
            try {
                FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/mvc/stock/ui/StockPricePanel.fxml"));
                root = loader.load();
                StockPricePanelController controller = loader.getController();
                controller.setProvider(stockPriceProvider);
                
                Scene scene = new Scene(root);
                
                jfxPanel.setScene(scene);
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            }
        });
        add( jfxPanel, BorderLayout.CENTER );
    }

The resulting NetBeans application is shown below.

Screen Shot 2015-06-12 at 1.43.45 PM

twitter: @RobTerpilowski
t
witter: @LimitUpTrading

Automatically Sorting a JavaFX TableView

With the SortedList implementation of ObservableList, automatically sorting a JavaFX TableView nearly works out of the box. In fact, it does work out of the box as long as you are adding or removing items from the list. In these circumstances, the list and the accompanying TableView will automatically resort the data. The case where the data isn’t automatically resorted is if the data in the existing rows change, but no rows are added or removed from the list.

For example, I have a TableView displaying various price information about a list of stocks including the last price, and the percent change from yesterday’s closing price. I would like to sort the list based on percent change, from lowest to highest as the prices change in real-time.  However since the app just loads the stocks into the list once and then never adds or removes items from the list, the TableView only auto sorted on the initial load, but did not automatically sort as the prices were updated.

Fortunately the fix proved to be fairly minor and easy to implement.

To start with, the application uses a Stock POJO which contains the following properties to represent the data. An ObservableList of these POJOs will be the basis of the data that the TableView will render.

public class Stock implements Level1QuoteListener {

protected StockTicker ticker;

protected SimpleStringProperty symbol = new SimpleStringProperty("");

protected SimpleDoubleProperty bid = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty ask = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty last = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty percentChange = new SimpleDoubleProperty(0);

protected SimpleIntegerProperty volume = new SimpleIntegerProperty(0);

protected SimpleDoubleProperty previousClose = new SimpleDoubleProperty(0);

protected SimpleDoubleProperty open = new SimpleDoubleProperty(0);

 

The first step is to implement a new Callback, tying it to the property we wish to sort in the table. When this property is updated it will trigger the table to resort itself automatically.

      Callback<Stock,Observable[]> cb =(Stock stock) -> new Observable[]{
        stock.percentChangeProperty(),
    };

 

The next step is to create a new ObservableList using the Callback above.

      ObservableList<Stock> observableList = FXCollections.observableArrayList(cb);
      observableList.addAll(stocks);

Finally the last step is to create a new SortedList using the ObservableList previously created and also passing in an implementation of a Comparator which will be used to determine how to sort the data.

      SortedList<Stock> sortedList = new SortedList<>( observableList, 
      (Stock stock1, Stock stock2) -> {
        if( stock1.getPercentChange() < stock2.getPercentChange() ) {
            return -1;
        } else if( stock1.getPercentChange() > stock2.getPercentChange() ) {
            return 1;
        } else {
            return 0;
        }
    });


    tickerTableView.setItems(sortedList);
}

That’s it. The video below illustrates the auto-sorting in action as the price of the stocks are updated in real-time.


twitter: @RobTerpilowski

JavaFX Application Thread Mysteriously Disappearing in Netbeans RCP / JavaFX App

I have a fair amount of pluggable infrastructure in place with the NetBeans platform for trading related applications. My latest application, “Atlas Trader” is being used to route our commodity trades through Quantitative Brokers. I want to take advantage of JavaFX for this project as it provides a cleaner MVC separation than Swing does, and also provides a lot of eye candy out of the box, such as animated transitions, translucency, etc.). I have been having strange issues however when attempting to incorporate this as a module to my NetBeans platform application.

I started out with a stripped down version of the platform, since I don’t need any of the Swing components and all the UI components with be within an JavaFX Scene, so have only included the following RCP modules:

  • org-netbeans-api-annotations-common
  • org-openide-modules
  • org-openide-util
  • org-openide-util-lookup

In my module’s “Installer” class, the restored() method kicks off the JavaFX app with the following calls:

Application.launch(MainApp.class);
Platform.setImplicitExit(false);

Screen Shot 2015-04-10 at 11.07.51 AM

All seems to be ok at this point. The app launches and displays the UI correctly. I can log in and get to the main screen of the application.

Below is the main screen in the application. The issues arrises when one of the commodity labels at the top of the screen is clicked. The expected behaviour is to display a new JavaFX componenet allowing the user to enter an order.

Screen Shot 2015-04-10 at 11.13.21 AM

The “CommodityHeaderLabels” at the top of the UI have the following action method defined.

@FXML
public void fireCommodityClicked() {

When one of these headers are clicked, an exception is immediately thrown, complaining that:

Caused by: javafx.fxml.LoadException: 

/Users/RobTerpilowski/ZoiCapital/JavaSource/QTrader/ZQTrader-Plugin/target/classes/com/zoicapital/qtrader/plugin/TradePanel.fxml:15

at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2605)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2583)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2445)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2413)
at com.zoicapital.qtrader.plugin.TradePanel.init(TradePanel.java:198)
... 10 more

Caused by: java.lang.NullPointerException
at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2920)

After drilling into the FXMLLoader class to find out what was going on, it appears that the “fireCommodityClick()” method is not being called from the JavaFX Event thread, and so it isn’t able to load the FXML file for the component that it needs to create when the item is clicked.

In fact, when running through the debugger, the JavaFX Thread is running prior to the component being clicked, but disappears when the component is clicked.

To make things even more difficult to understand, is that all the events leading up to this point are executed as expected in the RCP version of this application on the Java FX Application Thread. As I mentioned, I can log in to the application without any issues, and its not until one of these CommodityLabel components are clicked that the issue appears. Below is a screenshot of NB in the debugger with a breakpoint at the first line in the method that is called when the component is clicked. On the left side of the screen you can see the stack trace and that the current thread is the “AppKit Thread”, with the Java FX Application thread no longer present.

NB Screenshot

I set up a test project to run this application as a stand-alone outside of the NetBeans RCP, and things work as expected. The event method is called on the JavaFX Application Thread, and the resulting component is created and displayed as expected.

I can only think that there is an exception being swallowed somewhere, and that there may possibly be another NetBeans Platform module that is required in addition to the 4 modules that I mentioned at the beginning of this post.

I realize this post is a little short on the amount of code, but I’m looking for any other ideas on areas I could look at to further debug this issue.

twitter: @RobTerpilowski