David J McClelland

Experiences at the Intersection of Programming & Design

Archive for the ‘Techniques’ Category

Adding truncation feature to Axis Tick Labels in chart widget extension required the addition of dynamic properties.

Solution Phase One:

Use D3 to set titles on tick labels exceeding a user-configurable length:

if (thisWidget.truncateX !== 0) {
    d3.selectAll(widgetContainerId + '-chart .nv-x .nv-axis .tick text')
        .each(function (i) {
            var tick = d3.select(this);
            var fullText = tick.text();
            var truncText = fullText;
            // standard truncation with ellipses
            if (fullText.length > thisWidget.truncateX) {
                truncText = fullText.substring(0, thisWidget.truncateX) + '...';
            // preceding truncation with ellipses
            if (thisWidget.truncateX < 0){
                truncText = '...' + fullText.substring(Math.abs(thisWidget.truncateX), fullText.length);

I Considered using an algorithm based on available space but this was complicated by text tilt option and the fact that it would have to calculate every label individually. Instead I added a property for X and Y axis truncation to the widget IDE. Note that using a negative number performs truncation at the start of the label string instead of the end. This is handy when labels suffer from an overuse of Hungarian notation.

Negative value leaves n characters at the end of the label and places a preceding ellipses

Standard truncation replaces limits to the first n characters and replaces the rest with an ellipses

I Used the standard Thingworx platform Tooltip library

…with the Widget chart extension to apply a tooltip to truncated text label’s title.

// qtip jquery extension over titles in d3 axis
$('title').each(function () { // Grab all elements with a title element,and set "this"
        id : thisWidget.jqElementId,
        content: {
            text: $(this).text()
        position: {
            target: 'mouse',
            adjust: {
                x: 10,
                y: 10
        style: {
            classes: 'widget-barChart-tooltipStyle' + customTooltipStyleName,
            widget: false, // Use the jQuery UI widget classes
            def: false // Remove the default styling (usually a good idea, see below)
    // remove title element

I Removed the titles when I noticed browser tooltips poking through since titles are divs and not attributes in D3.

-12 truncation result

12 truncation result


I Used Qtip class name attribute to style tooltips according to widget property

This was the most confusing aspect of integrating the tooltips. Qtip lets you add a classname to the Qtip element that it puts on the Body DOM so you can create a style and have it apply to it (in style object in snippet above). Sounds simple! But QTip applies its own default class names to each tooltip on its own, and sometimes they superseded my custom classes. In the snippet above, classes is where a classname is defined, and widget and def are false to prevent the other classnames from being added by Qtip. The additional customToooltipStyleName is appended when the widget has a custom style applied to it. In this way, that classname matches the specific widget id, making it apply the custom style to that widget alone.

Default platform tooltip style

custom widget tooltip style

custom widget tooltip result


Solution Phase Two:

When multiple services provide data to Chart Widget, which one provides the label text?

I had sidestepped this issue in the original chart widget design by leaving out X-Axis Tick Labels. This was intentional: we released an MVP and wanted feedback from customers about what was important to them to include in a more elaborate solution. I added labels soon after release, but they only worked on single-service bound charts. Adding truncation to labels forced the issue that this effort should not be wasted on a feature that didn’t really work in every case.

Generate a service picker

Adding a property to the widget IDE to list off bound services seemed like it would be trivial, but this was not the case. There is no ready-made property that will display a drop-down list of data sources currently bound to a widget. There is no ready way to persist this information in the widget entity outside of the internal bindings definition, which is used by the Connections tab in the IDE and by Runtime to retrieve the data and update the widget display. This is not directly exposed in the widget API.

So, how to roll our own Bound Service Picker? I looked at how Collections widget used JSON to create and persist bindings and update the IDE properties from a service definition. I took this concept a significant step further by hiding the underlying JSON and using it to create a dropdown picker.

this.afterAddBindingSource = function (bindingInfo) { ...
this.afterRemoveBindingSource = function (bindingInfo) {...

These functions were the key to managing a list of binding: Every time anything is bound to the widget or unbound, one of these functions is called. The bindingInfo provides the name of the binding target property, and this enables selectively adding and removing dataSource names to a hidden string property that is constructed as a serialized array. The length of the array determines whether the DataSource picker is displayed in the IDE (since it is only required when 2 or more services are bound). The array also updates the selectOptions of the DataSource picker, which are the selections it displays in the dropdown.

Number of bound dataSources is reflected in properties. Each datasource has different labels

Short Labels from DataSource1

Long labels from DataSource2

Generate a Field picker

The same technique was used to populate a Field Picker. The contents of the field picker only needed to be retrieved when the first data source was bound, because every service bound to the Chart Widget has to share a common Data Shape. And the selectOptions of the Field Picker are the Field Definitions from the service Data Shape.

var dataShape = thisWidget.getInfotableMetadataForProperty(property) || {};

This function returns the fieldnames of a service when it is bound if it is called from within afterAddBindingSource() as value names. These are put in an array used to populate a Field Names dropdown property in the Widget IDE and serialized and put in a hidden string property for persistence.

The selected item in the pickers is persisted in the widget entity model and restored when the Mashup containing the widget Extension is reopened in Mashup Builder. If that were not the case, the selections can be monitored and set to hidden string properties as well. I set it up that way and then verified this additional step wasn’t needed.

Every Data Source has the same DataShape which in the example consists of these two field names.

Managing the Data Source and Field Name pickers

     * Invoked by the platform whenever the user binds a data source to a property on this widget.
     * @param bindingInfo <Object>        An object containing the newly created binding's properties.

    this.afterAddBindingSource = function (bindingInfo) {
        var thisWidget = this;
        var property = bindingInfo.targetProperty;
        var properties = thisWidget.allWidgetProperties().properties;
var seriesNum = thisWidget.getProperty('NumberOfSeries');
        if( seriesNum === dataSources.length && seriesNum < thisWidget.MAX_SERIES){
            thisWidget.setProperty('NumberOfSeries', thisWidget.getProperty('NumberOfSeries') + 1);
        // minimum binding requirement is met
        if (property.indexOf('Data') > -1) {
        //adding multiple data services to populate chart - only need one dataShape - they all must be same
        if (property.indexOf('DataSource') > -1) {
            thisWidget.setProperty('SingleDataSource', false);
            var dataShape = thisWidget.getInfotableMetadataForProperty(property) || {};

            // build up an array of datashape names and types to allow user to pick dataSource to 
            // provide x-axis label field
            dataSourceList.push({'value': property, 'text' : property});
            // also provide a simple list of data sources to runtime to match them to the dataSource 
            //x-axis label field

            // build field names list if it is not already defined
            if(String(thisWidget.getProperty('_dataShape')).length === 0) {
                for (var key in dataShape) {
                    // check also if property is not inherited from prototype
                    if (dataShape.hasOwnProperty(key)) {
                        var value = dataShape[key];
                        multiServiceDataShape.push({'value': value.name, 'text': value.name});

            properties['X-AxisLabelField']['selectOptions'] = multiServiceDataShape;
            properties['X-AxisLabelField']['isEditable'] = true;
            properties['X-AxisLabelField']['isVisible'] = true;

            thisWidget.setProperty('_boundDataSources', dataSources.join(','));
            thisWidget.setProperty('_dataShape', dataShapeList.join(','));

            properties['X-AxisLabelDataSource']['selectOptions'] = dataSourceList;
            properties['X-AxisLabelDataSource']['isEditable'] = true;
            properties['X-AxisLabelDataSource']['isVisible'] = true;


     * Invoked by the platform whenever the user unbinds a data source to a property on this widget.
     * @param bindingInfo <Object>        An object containing the newly removed binding's properties.

    this.afterRemoveBindingSource = function (bindingInfo) {
        var thisWidget = this;
        var property = bindingInfo.targetProperty;
        var properties = thisWidget.allWidgetProperties().properties;

        // remove the datasource that was unbound
        for(var i = 0; i < dataSourceList.length; i++){
            if(dataSourceList[i].value === property){
                dataSourceList.splice(i, 1);

        // dataSources is not in same order as dataSourceList so splice separately
        for(var i = 0; i < dataSources.length; i++){
            if(dataSources[i] === property){
                dataSources.splice(i, 1);

        thisWidget.setProperty('_boundDataSources', dataSources.join(','));

        if (property.indexOf('DataSource') > -1) {

            // the X-AxisLabelField doesn't provide any functionality when there is one binding
            if (dataSources.length <= 1){
                properties['X-AxisLabelField']['isVisible'] = false;
                properties['X-AxisLabelDataSource']['isVisible'] = false;

        //all data bindings were removed - sound the alarm!
        if (dataSources.length === 0 && property.indexOf('Data') > -1) {


I used to use a set of bulky cables to run two PCs from a single keyboard, mouse and monitor when monitors and laptops were expensive. Once I had multiple monitors running video from laptops I found a software that does the keyboard and mouse sharing via TCP/IP (internet) and I gave up on the cables.

There are free and commercial KvM utilities, I use one called Synergy. (I use a small v in KvM since it doesn’t really do anything with video but we still use the old term.) It is commercial, although you can use an old version for free with no support. That version is the one I started, so I have never upgraded and it still works fine. It also allowed me to use my MacBook Pro as a second monitor for my PC. They have a video about how it works. That old free version has a very confusing setup and UI: if you are just getting started, spring for the commercial version.

One thing I noticed recently after installing it on a new laptop is that Synergy would stop working whenever I ran a screen or video capture utility, such as Snagit, Camtasia, Jing or even Windows Snipping Tool. Not only that, it would seem to get the alt, ctrl and shift keys stuck as if they were pressed down, and this would persist after I had stopped capturing. This would prevent saving screen captures and generally any interaction through the keyboard got hosed – very frustrating! For a while I tolerated this by using my laptop keyboard and trackpad during captures and then tapping the alt, shift and ctrl keys repeatedly on both laptop and main keyboards to reset things. (And then tell Windows “No I don’t want to turn on Sticky Keys – argh!”)

The correct solution to this is the always run Synergy as Administrator on the system where you are capturing- it will retain control of the keyboard and mouse during all capture sessions that way. If you don’t have admin rights, you probably can’t install and run a software KvM in the first place.

  • Filed under: Techniques
  • Populate a Grid Widget with JSON data in Thingworx


    The Grid Widget is very useful for displaying and selecting tabular data. I will show how JSON data (from this site) can be processed in Thingworx to display existing content in different ways.


    ThingWorx Server and a service that emits JSON data via standard REST requests.

    Data Source

    For a source of JSON data, I decided to use this website. WordPress.com offers a free JSON API that will process any self-hosted site through a redirection request URL. The only requirement is to set up an application key to authenticate the self-hosted site to WordPress.com.

    I tested the JSON API by entering a URL with my site URL designated as the source:


    This request returns JSON text of all published posts on this site. It is a convenient way to examine the data structure in order to select data for specific displays and other purposes.

    Thingworx Service (Web Service)

    To get the posts to appear in a Grid Widget in Thingworx, a service must be created on a Thing Object that can emit a request to the URL that returns the JSON. Thingworx supplies Javascript code snippets with the outline of the required code to accomplish this. The service editor provides a test feature that is very helpful in debugging the code and ensuring a connection occurs and expected data is returned.

    ThingWorx Service

    ThingWorx Service

    ThingWorx Datashape (Table Definition)

    ThingWorx requires that external structured data such as JSON and XML conform to a table that you can define. This is called a DataShape in Thingworx nomenclature. I chose 4 fields, including post Title, Author, Content and URL. Title and URL are strings, Author is JSON and Content is a String

    Thingworx DataShape

    Thingworx DataShape

    ThingWorx Mashup (UI Layout)

    Next, I created a Mashup in Composer to display the Grid Widget and an HTML Text Widget.

    ThingWorx Mashup

    ThingWorx Mashup


    Mashup Runtime

    Mashup Runtime


    Now that we have a populated grid and an HTML Text Box displaying the content of each selected row in the grid, we can add more fields and customize how they are displayed in the grid.

    Add More Fields

    Added Fields

    Added Fields

    Added Fields In Service

    Added Fields In Service

    Update Grid Columns

    Customize column displays by selecting Configure Grid Columns  from the widget context menu. The author avatar displays as an image because the column renderer tab settings were changed to use an IMAGELINK renderer.

    Configure Column

    Configure Column

    Updated Mashup

    Mashup Runtime

    Mashup Runtime

  • Filed under: Techniques
  • Intellij IdeaCygWingitorange@2x

    I didn’t find much existing basic documentation on how to get started with scripting in earnest, so I decided to fill the gap with my own experience. I had never been an avid user of command windows or terminals or scripting, and I admit to complaining that Cygwin is be a confusing heap. But that hasn’t stopped me from realizing their benefits, and I am ready to give them the respect they deserve since they have saved me time and drudgery.

    Solving Script Amnesia

    A successful script automates some tedious activity on the OS and is soon forgotten. That’s my problem: when I need to write or edit a script its hard to pick up where I left off or remember arcane syntax that I don’t use anywhere else. I don’t write scripts all day, so I often don’t remember where I put it, what environment I edited in, let alone some arcane syntax and other context information.

    I should have realized a long time ago that if a script is worth writing, it is worth safeguarding and properly maintaining like any source code. But script editing happens in spurts as a means to an end – it’s hard to justify taking the time to build up an infrastructure and become more proficient. This post documents how I set up a script repository and IDE using Git, Bitbucket, IntelliJ, Cygwin and some assorted environmental variables. So this documents my effort to get a a scripting environment set up that I can get familiar with and rely on. I’ll know it’s successful if I start writing more scripts because I feel more confident that I will get a longer return from the effort.

    Before I set up my scripting environment I asked my self some questions to help determine what tools and techniques I would need, and I encourage you to do answer these as well:

    Scripting Environment Questions:

    • Portability: How portable does my script need to be?
      • What OS(s) will it run on? My case: Win/Mac/Linux
      • What user(s) will use it? Me/Coworkers/My boss/Continuous Integration
    • IDE? Can I edit my scripts in the same IDE I use for everything else? Yes (detailed follow)
    • Extensibility: If my script can’t do everything natively, is there a strategy to add functionality? (Yes, details follow)
      • For example, if your script needs to do a REST call, do you: script a browser? import a cURL library?
    • Conventions: Is there a convention I can follow to put my scripts where both the OS and I can find them without tweaking? (Yes, requires some care)
      • For example: home/user/bin

    My answers lead me to a create a setup that prioritizes flexibility across OS and users and tries to follow general conventions. So, it should work for anybody, but you can sacrifice some of the generalization for your own convenience if you want to.


    Once you combine Windows with another OS you are probably going to run into Cygwin as your go-to solution because you can write bash scripts that can run on Windows, MacOS and Linux. It is still very possible/maybe necessary to write Windows-only scripts in Cygwin. All my scripts are .sh except some narrow Windows cases.

    Portability also pertains to editing and running scripts on multiple machines in multiple user accounts. It means creating a project definition that can be put under version control to allow me to edit and run scripts on any machine as any user. To do this I followed conventions regarding where to house scripts (see Conventions below) and set my cygwin user folder as the project root and committed this to BitBucket using Git.

    IDE Support

    Maybe it should have been obvious, but it took me awhile to decide that I should strive to use my regular editor to edit scripts. I use IntelliJ, and I found a plugin called BashSupport that supports syntax highlighting, rename refactoring, documentation lookup, inspections, quickfixes and such. I can also run scripts from run configurations within IntelliJ- not sure if that is due to BashSupport or not honestly. Before that I used Notepad++, or simply Notepad. Another big advantage of using an IDE: it creates a project definition so you can reopen the project and see your scripts! Again, should have thought of this earlier, but my scripts were all small and scattered and this seemed like a heavyweight tank cracking a nut.


    Cygwin has cultivated a large library of plugins that scratch the itch of various developer needs. It is likely to cover any requirement I will have. Install Cygwin to C:\ and don’t install any optional components. Save the installer (setup-x86_64.exe in my case) in the cygwin folder inside a folder you create called installer. Cygwin will create a cache of the plugins library in there. You will need the installer if you ever decide to install a plugin, so its a good idea to keep it with the project folder instead of losing in in the downloads folder like I have done.


    Tip: In Cygwin Shortcut select Preferences: Shortcut Pane: Click Run as Administrator


    Cygwin tries to follow conventions whenever possible. It puts a directory structure that mimics Linux root, but it is located inside the Cygwin installation folder. Instead of accepting the default “Program files” location, install cygwin at C:\ to avoid spaces in any paths. My user dir is therefore: C:\cygwin64\home\[windows username]\bin. I added bin to .bashrc so I can run scripts from anywhere in Cygwin.

    Running Scripts

    From Intellij: As I mentioned, you can run shell scripts from within Intellij using run configurations. This seems like a lot of work after getting past the cool idea factor. It doesn’t open up any debugging options as far as I can tell. It’s a good idea to check the “Show this page” box to fill in any necessary arguments before running a script.


    Intellij Script Run Configuration


    Script output in Run Output of Intellij

    From Cygwin: cd bin, then ./script.sh to execute. Or add bin to .bashrc and execute script.sh from any location. Add Cygwin to context menu in Windows.

    From Git Bash: Open it from your bin directory to run a script on a Windows dev box lacking Cygwin. Otherwise useless because it is not extensible and conventional.

    You can run Cygwin in the IntelliJ terminal or in a terminal emulator like Conemu as well – Google for details.

    How to Add a Custom Element to a Polymer Project


    Starting with a project build with Yeoman (Yo Polymer), I add a custom element and display it in the index file. In addition, how to set up a project to build with Vulcanize and why, and how custom elements relate to the data model in Polymer is discussed.


    polymerSandbox with djm-nameTag element

    I made a copy of one of the existing custom elements in the Yo-Polymer base project. I replaced the contents with a nametag example element from the Polymer data binding topic on their website. I named it with djm- prefix in order to satisfy the Polymer requirement that custom element names contain a dash while also adding a namespace to it by referring to my initials.


    <link rel="import" href="../../bower_components/polymer/polymer.html">
    <polymer-element name="djm-nameTag" attributes="">
        This is <b>{{owner}}</b>'s djm-nameTag element.
        Polymer('djm-nameTag', {
          // initialize the element's model
          ready: function() {
            this.owner = 'Rafael';

    Then I added the element to the index.html file body.


    I expected to have to add an html import to the index file but there were no imports for the other elements. I realized that they were being imported via the vulcanize library method.

    <!-- build:vulcanized elements/elements.vulcanized.html -->
    <link rel="import" href="elements/elements.html">

    I added a djm-nameTag entry to elements.html

    Then when I ran

    grunt build

    grunt cleaned and rebuilt the dist directory and added djm-nameTag element to the elements.vulcanized.html file.


    polymerSandbox dist directory including elements.vulcanized.html


  • Filed under: Techniques, Tools
  • Building a Polymer Project From Scratch


     nodeJs + npmLogo + bower + yo + gruntLogo =polymerLogo

    1. Download and install NodeJs
    2. Make sure nodeJs is on the system PATH.
    3. Open a command window and enter node -v
    4. Install Node Package Manager (NPM): Enter npm install npm -g
    5. npm install -g grunt-cli
    6. npm install -g bower
    7. npm install -g yo
    8. npm install -g generator-polymer
    9. Create a project directory and navigate inside it from command: mkdir my-new-project cd $_
    10. To build a polymer skeleton project: yo polymer

    More on yo polymer scaffolding generator


    Scaffolded Polymer Project Directory after yo polymer



    dist directory contains Polymer site root after grunt build

    Run server:

    grunt serve


    HTML outputs to default browser automatically on port 9000

    Test (Local):

    grunt test


    HTML outputs to default browser automatically

  • Filed under: Techniques, Tools
  • Learn-along Maven 3: Integrating Selenium

    maven  Intellij Idea selenium

    In Learn-along Maven 3: Adding Dependencies I shared the way I add dependencies to a project to enable frameworks and libraries via Maven Project Object Model (POM).

    The dependencies satisfied the requirements for working with Java Server Pages, Struts 1.x, JBoss, testNg and Selenium. Together these will work with Java and JBoss Application Server to provide a testable web application.

    Since I started with the Hello World archetype I have some work to do to enable serving web pages with my application. All  the application can do from the start is print “Hello World!” out in the console, and verify that it works via a test class using jUnit.

    The Java Server Pages dependency provides a ready-made framework for delivering web pages via JBoss. Following the greased path outlined by the documentation, I added a web folder at the same level as src, and created a web page within it named “index.jsp”. This filename is the default for jsp/jBoss and will open when the directory containing it is reached in a browser. Then I added a folder within web named WEB_INF, and created a web.xml file in it which is used to define the jsp configuration for a j2ee compliant appllication server such as jBoss.

    To do this I need to create a web page within the project. I will  configure it within a standard web application format that JBoss can process and then deliver at a URL on my local computer. Then I will write a Selenium test that uses TestNg annotations and assertions to automatically open and verify that the page is launched in a specific browser and contains the content that I included when I created the web page.

    The Web Page

        <title>Welcome to simplest-struts</title>
    <p>simplest struts</p>

    Create a folder named “web” and save this html as “index.jsp” in it.


    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"


    package com.davidjmcclelland;
    import com.thoughtworks.selenium.SeleneseTestBase;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.testng.annotations.BeforeClass;
    import org.testng.annotations.Test;
    import org.testng.annotations.AfterClass;
    import org.apache.log4j.Logger;
    import static org.testng.Assert.assertTrue;
    public class SeleniumTest extends SeleneseTestBase {
        public static WebDriver driver = new FirefoxDriver();
        private final Logger logger = Logger.getLogger(SeleniumTest.class);
        public SeleniumTest(){
        public void setup(){
            logger.info("Setup class: " + this.getClass().getName());
        public void titleTest(){
            assertTrue(driver.getPageSource().contains("simplest struts"));
        public void tearDown(){

    The Selenium test running from IntelliJ

  • Filed under: Techniques, Tools
  • Learn-along Maven 3: Adding Dependencies

    maven  Intellij Idea 

    In Learn-along Maven 3: Hello World Tests Compared I compared running tests on a Hello World Java app using Intellij and various Maven approaches.

    In this post I will compare methods for adding libraries/dependencies. Where I am going with this is to take the Hello World archetype and make it into a webapp project and then test it with Selenium.

    • Add Java Server Pages
    • Add Struts 1.x
    • Add Selenium
    • Test locally in browser
    • Test in browser from Jenkins

    Libraries vs Dependencies...

    Adding libraries via the Intellij 12 module tab in project settings is not the same as adding Maven dependencies. I guess that seems obvious as I write this, but I would argue that if you create a Maven project it should behave consistently in a Maven-centric way. But when I add apache-log4j in the Project Structure dialog and select Library->Via Maven, a dependency is not added to the project POM file. The dependency storage format dropdown is a clue: the choices are IntelliJ or Eclipse formats, not Maven POM. The junit library that I added to the POM file manually is listed in Dependencies and has the prefix Maven: in front of it to indicate it is in the POM.

    I was hoping to find an integrated method for adding dependencies to the POM using IntelliJ 12 or 13, but so far I still find that pasting in a dependency block from Nexus Central repository is the best and easiest method.

    For several reasons:

    1. I am able to have a good look at the origin and version of the resource I am getting
    2. I am certain the dependency gets in the POM
    3. The resource is stored in the .m2 directory in the package where it belongs.
    4. I don’t have to manually figure out where to put the resource in the .m2 directory.
    5. I can update the resource by editing the POM entry and Intellij will download and install the update in the background

    Nexus Central vs. Intellij

    Nexus Central Repository shows resources in context, and rolled up in far fewer choices than a dropdown.

    A dropdown is insufficient when there are over 200 valid selections for “junit”

    A Library downloaded from a Maven Repo should default to saving in the appropriate package in the .m2 directory. I don’t want to guess where to put it when the correct answer should be in the artifact’s POM.

    Check the setting to Import Maven projects automatically


    This aspect of developing in Java/Intellij is clunky compared to other stacks I have used. For example, to move a project from a simple “Hello World” command line test to a Struts WebApp required a lot of digging around to find the required libraries and versions- I finally “cheated” and opened the POM of another project and grabbed the entries form it to save time. There is no “Make this struts” button.

    A veteran Java developer would counter that “you just need to know what you’re doing.” That is true, of course. I know I can create a Struts project from an Archetype and get started. A wise developer needs to know what they are not doing. I need to focus my effort on developing what makes my project different and important enough to be funded. A strong library feature is a critical aspect of this.

    Once I found what I thought were the correct libraries/versions for Selenium, testNg, Struts and JSP were added to the POM there were several problems. Not having a real user interface to handle dependencies meant spending a lot of time Googling and comparing to other project to figure out. Eventually I got it sorted out and currently can run a test that opens a browser window to the page served by the webapp project.


    <?xml version="1.0" encoding="UTF-8"?>
  • Filed under: Techniques, Tools
  • Learn-along Maven 3: Hello World Tests Compared

    maven  Intellij Idea console2Logo

    In Learn-along Maven 3: IDE vs CLI I compared creating a Hello World Java app via Maven using command line vs with IntelliJ using a Maven extension. The result was pretty much identical, but the process was slightly different between the two. Both projects ran green on Jenkins, although they really don’t do much and the test class is a bogus assertTrue(true).

    Now I will I will change the test to evaluate that the “Hello World” String is created as an accessible String and compare running the test

    • within Intellij,
    • within Intellij via Maven plugin,
    • with Maven via command line, and
    • via Jenkins.

    Change Main class and test assertion...

    Original archetype Hello World Class

    Testable Hello World class now has a variable message

    Replace the test assertion with this:

    assertTrue( App.message.equals(EXPECTED_STRING) );

    Test in IntelliJ...

    Build and run the test in Intellij by right-clicking the test class window tab or file icon.

    The target directory contains the build.

    Maven Test in IntelliJ...

    Maven Intellij plugin expands from the Right side by default, click Test in lifecycle…

    Test via Maven does not put empty annotation folders in target, otherwise the output looks the same as running the test from Intellij right-click menu, but its important to note that it is *not* the same thing.

    Maven Test from cmd.exe...

    mvn clean test

    Cmd shows the same information that is displayed in the Run log window in Intellij when you run a test via the Maven plugin.

    Output target directory was the same as running the maven plugin from within Intellij.

    Maven Test in Jenkins...

    Looks like the test runs great on Jenkins

    Wait something’s wrong: all Jenkins did was build an empty target folder structure. Nothing was run or tested at all. It’s a freestyle project – you have to enter the Maven commands.

    Make sure you enter “Invoke top-level Maven targets” which is the same thing as what was entered in the command line example.

    You should see test results at the bottom of the console log view.

    Maven’s workspace target directory now contains class files.


  • Filed under: Techniques, Tools
  • Learn-along Maven 3: IDE vs CLI

    maven  Intellij Idea console2Logo

    Is there a difference between running Maven from within an IDE or directly in a command line? There shouldn’t be, but sometimes I have run into situations where I get different results between the two.

    When anything unexpected happens I tend to revert to the command line as a trusted source of truth. I don’t want my use of Maven with an integration tool like Jenkins, which requires a certain level of familiarity with its workings- to be limited if the IDE becomes a Maven crutch. On the other hand, if I can integrate my IDE with Jenkins via Maven there may be some interesting opportunities for automation and integration.

    So this will be a two-way comparison of Maven use and development via Intellij IDEA, which offers pretty good Maven support, and Console 2, the command line tool I use that combines Windows com, Powershell and Cygwin.

    Compare using Archetypes...

    Using IDEA to build archetype vs command line. Note that IDEA “sees” the POM in the my-app folder and claims the folder icon, but there is no .iml file present.

    Generating the archetype from within IDEA had the advantage of IDEA assigning the Maven type to the project from the start. The project I generated from the command line would have to be imported into IDEA as a Maven project to be worked with on that basis, and would then be identical to the one I created within IDEA.

    When I opened the CLI-created project directly from IDEA (as opposed to import Maven project) there were no project contents

    When I imported the CLI-generated project as a Maven project it became almost identical to the one IDEA generated in the first place.

    The IDEA-generated Archetype for comparison. Note I opted for the IDEA project settings as folder instead of single file – hence the .idea folder in this one only.

    One Difference Noted...

    This popped up when I reopened the IDEA-generated project. I thought IDEA already did this?

    after I clicked “auto-update” the dependencies folder was added and populated in the Maven panel. This was already present in the CLI-generated archetype.

  • Filed under: Techniques, Tools
  • Categories

    Finger Lakes, NY

    United States of America

    Subscribe via Email

    Enter your email address to subscribe to this blog and receive notifications of new posts by email.