OCPJP, Talks and the Spring Boot Buch

January was an intense month, even if it started with a week off. I didn’t have vacation during the seasons like my wife. Sad thing: We couldn’t really spend the vacation together, but that seems to be the standard when both parents are working and the number of holiday days doesn’t fit the number of free days the kids have.

In the last year quarter of 2016 I decided that I should finally upgrade my good, old Sun certificate from SCJP 5.0 to a shiny, new Oracle OCPJP 8.0. The incentive came from Tim. I didn’t know before that there was an upgrade path and I didn’t to pay for both associate and professional. But that upgrade paths exists and last week, I scored 93%. It was actually fun (yes, I enjoy those things). As preparation I read both OCA and OCP Java 8 Study Guide by Jeanne Boyarsky and Scott Selikoff. The quality varies, but overall, the books are ok. If you do prep exams, I’ll really recommend enthuware. Much cheaper than the Oracle recommend sell from selftestsoftware.com. The buying process of the later is frustrating and they contain a lot of plain wrong questions.

I did my my talk database centric applications with Spring Boot and jOOQ based on that series at the Spring Meetup Munich. It was real good fun and I like the results very much. But preparing for the talks stresses me a lot. I want to give my best and I’m not yet relaxed. But, I’m gonna train this. I’ll be at JUG Essen on April 26th and in June in Cluj with Vlad at the Transylvania Java User Group who have probably the coolest of all Dukes. Vlad and I are gonna speak about getting the most of your persistence layer.

As early as November 2016 I started looking for a publisher for my idea writing a German Spring Boot Buch. I’m really happy that dpunkt.verlag took my offer. I have been working on the manuscript since mid December and it starts to take shape.

It’s an interesting process. The first book I contributed to is arc42 by example (by the way, version 7 of arc42 was just released this month). Basically, I had written everything at this point and we did proofread and everything ourself.

Having a lector does help a lot so far and it feels very different than just scribbling down whatever is in ones head.

For me personally it was a good thing to “pitch” the book idea. Helps getting structure into the content.

This is a screenshot of how I’m working at the moment: I’m writing LaTeX inside Texpad on a Mac. Next to it is Safari. Click on it for a larger view.



My first draft was indeed an Asciidoctor version and I already had setup a continuous compilation pipeline that worked quite well. The syntax is ok, too and what is really nice is including examples, like a did here. But dpunkt.verlag takes either LaTeX or Word and I didn’t want to cross-translate stuff. I used to write a lot of LaTex during university and it came back instantly.

Texpad is a good piece of software for writing LaTex. It supports includes and inserts, makes it really easy to cross reference stuff, draws a good outline and has a simple todo feature, basically everything I need. The sources are of course versioned in a private repo so I can write from everywhere. Sometimes I have to write some paragraphs in plain text in Pages or Word to get the flow right while not being disturbed by LaTeX commands, but that is fine for me.

If you want to read about writing a book in Asciidoctor, have a look at Thoughts on Java: Thorben has just switch to Asciidoctor away from the Leanpub Markdown dialect for his first book.

So far I’m following my outline rather closely and the first milestone was just done in time today. Even I know many things by heart now, I do a lot of research, too. I’ll keep my notes in a separate file inside the project with todos on them. Really easy to get back to. While working myself through the documentation, I took the time to file some PR over at Spring Boot itself, fixing stuff in the documentation (and, by the way, got my first bigger PR into Spring Boot 1.5, the @DataMongoTest).

And I actually bought a Duden on paper. It’s slower, but doesn’t distract me. Have a look at Judiths page to see how other writer work.

Apart from that, I’m doing a lot of examples. They are already only at the official Spring Boot Buch repo: github.com/springbootbuch.

What I don’t do is writing Mind Maps of any kind. They just don’t work for me.

The book will appear closely to Spring Boot 2.0 by the end of the year.

At the end of February, I’m gonna publish the outline. Bye then it shouldn’t change much anymore.

| Comments (1) »

31-Jan-17



Using JShell in NetBeans

With Java 9 comes JShell, the first official Java Read-Eval-Print-Loop (REPL). The Takipi blog has a nice article out, just in case you don’t know nothing about it. Read it here: Java 9 Early Access: A Hands-on Session with JShell – The Java REPL.

I’m gonna show you today a short screen cast using the current nightly build from the free and Open Source IDE NetBeans. NetBeans allows to run JShell not only with JDK 8 but also agains an opened Maven project, containing all the dependencies from your POM file and the classes of your project.

The first part is a recap what JShell REPL is all about. In the second part, I’m gonna use my DOAG 2016 project. The project is a database centric project using jOOQ for creating database queries.

I’m gonna open up a JDBC connection to a local Oracle Database and execute some queries, from really simple ones to the ones I used in this talk:

What is it good for? In this case I can design complex database queries, try them out, having all the NetBeans features and tools at hand without going through a save / compile / reload whatever cycle. The NetBeans nightly has a lot of rough edges, sure, but you see the potential here.

I also tried starting up Springs application context, but that didn’t work for me yet. That would also incredible useful, especially in regard to generated Spring Data repositories.

| Comments (0) »

19-Dec-16


Java: 2016 recap

As last year I’m gonna write a short recap here. In global life, 2016 wasn’t a good year, in my private and work life however, 2016 was the best year in a long time. Java activity started early 2016, first with an Euregio JUG event having Bert-Jan in Aachen, NetBeans day in Utrecht and Java Land in Brühl. Also in the pictures Toni, Geertjan, René, Rainer, Josh and Adam:


I’m inclined to say that this:



changed everything again. I’ve been visiting conferences now for years and they started to become really awesome after having some great friends in the community but I never spoke. I changed that for good in May at Spring I/O and it was a great event. Thank you Sergi for putting your trust in me and René Glen from above for giving me great feedback for my first talk!

Michael^2, Geertjan

I continued speaking in a small NetBeans event in cologne and spoke about NetBeans, Maven and Spring Boot, meeting Michael Müller, Geertjan Wielenga and Stephan Knitelius.

Speaking of NetBeans: My friend Geertjan from Oracle, seen in disguise in the picture below, proposed me as member of the NetBeans dream team. What an honor!

Roughly at the same time, Red Hats Vlad Mihalcea, Developer Advocate for Hibernate, not only author of FlexyPool but also the other the definitive guide to all things persistence with Java named High-Performance Java Persistence started a series of great interviews on in.relation.to and invited me to join that list. Thank you again, Vlad!

In November I spoke again, at W-JAX 2016 and also at DOAG Konferenz und Ausstellung. It was an honor to be there:


Throughout those days these with Lukas, Henning, Axel, Niko, Christian, Matthias, Michael, Wolfgang, Oliver and Kai:

Even if I really get nervous all the time, speaking at this conferences was a valuable experience and I’ll try to continue that, starting early in 2017 at the newly founded Spring Meetup Munich together with Michael Plöd from InnoQ. If you think a talk about anything Spring and Databases or how to work with them using NetBeans would fit your JUG, please, drop me a line.

I wrote a lot this year and could publish several articles on German and English JAXenter which I collected on my about page. Apart from that stuff I wrote 35 blog posts this year here… Many of them got featured on the Spring blog, the jOOQ community page, in both Eugens and Thorbens Java Web weekly newsletters. Thank you Thorben, Eugen, Lukas and Josh.

The first book I ever wrote sold over 700 times which surprised me a lot. Have a look, Arc42 by example.

I managed to organize 6 events at our Euregio JUG, having Bert Jan Schrijver, Johan Vos, Max Wielsch, Manuel Mauky, Gernot Starke, Geoffrey De Smet, Carola Lilienthal and Mark Paluch:

Running this JUG is incredible rewarding: Not only I learn a lot of stuff, but can meet and talk with awesome people who love to share their knowledge and I’m looking forward to continue this in 2017. If you want to visit Aachen, please contact me: michael@euregjug.eu and we arrange something!

with Mark Heckler

Also, as a visitor: Go to a JUG at your place. In Germany, there’s one easily reachable from nearly everywhere in Germany, see the iJUG website. There’s also a curated map of JUGs worldwide, see Java User Group & events. It’s really easy to learn first hand knowledge from the experts or just have drink and talk. Invite others and convince them that those meet ups are great places. Smaller conferences like J-Fall, organized by the nl.JUG are also a day worth spent!

with Bruno Borges

Oh and by the way: In my last years Christmas holiday, I wrote the site for the Euregio JUG using Spring Boot and some other tools and it has been running on a sponsored Pivotal CF account for a year now. Really easy to deploy, using marketplace services like various databases, Elasticsearch and more is a no-brainer thanks to automatic reconfiguration of Spring Boot. Highly recommended!

The community we have in “Java land” is one of the most important assets, despite having sometimes a heated discussion over a few topics (I *have* to create an insult con some time), but that’s fine… The selfies in this post are my tribute to this community. You rock!

Also, a big thank you to my company ENERKO INFORMATIK, making it possible not only work on the stuff I like but also running a JUG amongst other stuff.

But most important, thank you to @tinasimons, wife, mother, developer and one of the hardest working persons I know and the one person I can always rely on. I’m so glad that she supports the ideas (and there are quite some right now) I have for next year. Here are just 11 years from 16 we have spent together in two pictures:


| Comments (2) »

10-Dec-16


Oracle JET: JavaScript components for mere mortals?

The final post in this series is about adding a front end to the analytic queries created with jOOQ and published through Spring Boot / MVC throughout the previous posts:

  1. Database centric applications with Spring Boot and jOOQ
  2. Create a Oracle Database Docker container for your Spring Boot + jOOQ application
  3. Take control of your development databases evolution
  4. An HTTP api for analytic queries

Deciding on a frontend technology for web applications

As much as I still like server side rendered HTML, there is some great stuff out there ready to use. I have written about creating a Anguluar 1 front end for a Spring Boot app nearly two years, so I had to research current options.

There’s quite a few buzz around

Alexander Casall did a very good presentation at W-JAX last week which of those techniques is the right choice for you. They both do have very different approaches. ReactJS focuses more on a modern programming paradigm where Angular 2 provides a more complete solution in terms of how one structures an applications, provides dependency injection and so on (On my todo list is an upgrade to above posts, where I will showcase upcoming Spring Framework 5 / Boot 2 with Angular 2).

What both Angular 2 and ReactJS are missing for the use case developed during in this series however, providing fast access to a lot of business relevant data, is a set of curated UI components, especially collections and data visualizations. I know, there is great stuff out there, but all must be carefully selected to work together.

This is where Oracle JET comes in. To quote Oracle:

“It’s a collection of open source JavaScript libraries along with a set of Oracle contributed JavaScript libraries that make it as simple and efficient as possible to build applications […]”

The sales pitch ends up in “consuming and interacting with Oracle products”. Well, you can do that, too.

I think more like a curated set of well proven open source modules of Oracle JET. It basically provides

  • RequireJS for managing used modules inside your scripts
  • Knockout. for providing two-way bindings between models and views
  • jQuery
  • jQuery UI which is the foundation for the great list of UI components included

Getting started with OracleJET

A new Oracle JET application can be created with a Yeoman generator which comes in various flavors: A basic starter which provides only the basic project structure and an empty page, a nav bar starter that has a responsive side bar and a starter that already provides hooks for going native through Cordova.

I personally prefer NetBeans 8.2 for those kind of tasks:



Geertjan has a nice article up, that explains in detail whats new in NetBeans 8.2 for Oracle Jet: https://blogs.oracle.com/geertjan/entry/updates_to_oracle_jet_mooc.

You have several options to use an application generated like that. One is using the provided grunt tasks like grunt build and grunt serve and especially later, when going to production, grunt build:release which does all the black magic of minimizing and optimizing your views and models. Again, you can use NetBeans for those tasks:



I do have a second Oracle JET based application up and running which is the admin backend of my user groups site, available here. This application is build as described above and then deployed to Pivotal CF using the static build pack.

The demo

Checkout the full source michael-simons/DOAG2016 here!

In the demo for DOAG Konferenz und Ausstellung I have chosen a different approach. Consider you want to deploy your analytic query together with an easy to use frontend: All static resources you put into src/main/resources/static are delivered “as is” by the embedded application container of your Spring Boot application, Tomcat being the default as of writing. This is what I did in #8158f5a (the commit is really huge, containing all the small JS files…). The single page application (SPA) is prefixed with “app”, so that I can display my carefully crafted Spring Boot loves jOOQ banner on the entry page before 😉

Note This works quite well, but I wouldn’t want to deliver the huge bulk of those JS, CSS and HTML files this way into production! I wanted to have a single, deployable artifact with a build process I can demonstrate in 90 minutes, even to non JavaScript developers. In production make sure you use the above grunt build:release target before this stuff reaches your customers browser!

Oracle JET uses Knockout for data binding, which is a prominent representative of a Model-View-View Model (MVV) framework.

A model that makes use of the query that provides the cumulative plays of artists by day from the previous post may look like this, see viewModels/artists.js:

define(['ojs/ojcore', 'knockout', 'jquery', 'moment', 'ojs/ojselectcombobox', 'ojs/ojchart', 'ojs/ojdatetimepicker'],
        function (oj, ko, $, moment) {
            function artistsContentViewModel() {
                var self = this;
 
                // The array containing all artists from api
                // Use the ojCombobox to implement server side filtering instead
                // of my brute force approach getting all artists
                self.allArtists = ko.observableArray([]);
 
                // We need this to store and get the selected artists...
                self.selectedArtists = ko.observableArray([]);
 
                // Load the artists data
                ko.computed(function () {
                    $.ajax({
                        url: "/api/artists",
                        type: 'GET',
                        dataType: 'json',
                        success: function (data, textStatus, jqXHR) {
                            self.allArtists.removeAll();
                            for (var i = 0, len = data.records.length; i < len; i++) {
                                self.allArtists.push({value: data.records[i][0], label: data.records[i][1]});
                            }
                            self.selectedArtists.removeAll();
                        }});
                }, this);
 
                self.fromValue = ko.observable('2016-01-01');
                self.toValue = ko.observable('2016-03-31');
 
                self.areaSeriesValue = ko.observableArray([]);
                self.areaGroupsValue = ko.observableArray([]);
                self.dataCursorValue = ko.observable('off');
 
                self.topNTracksSeriesValue = ko.observableArray([]);
                self.topNAlbumsSeriesValue = ko.observableArray([]);
 
                self.chartLabel = function (dataContext) {
                    return dataContext.series;
                };
 
                var updateCharts = function () {
                    self.areaSeriesValue.removeAll();
                    self.areaGroupsValue.removeAll();
                    self.dataCursorValue('off');                                        
                    self.topNTracksSeriesValue.removeAll();
                    self.topNAlbumsSeriesValue.removeAll();
 
                    if (self.selectedArtists().length === 0) {
                        return;
                    }
 
                    var dateRange = {
                        from: self.fromValue(),
                        to: self.toValue()
                    };
 
                    $.ajax({
                        url: "/api/artists/" + self.selectedArtists().join() + "/cumulativePlays",
                        type: 'GET',
                        data: dateRange,
                        dataType: 'json',
                        success: function (data, textStatus, jqXHR) {
                            if (data.records.length === 0) {
                                return;
                            }
 
                            // Need the artists labels for the series
                            var artists = self.allArtists().filter(function (elem) {
                                return self.selectedArtists.indexOf(elem.value) >= 0;
                            }).map(function (elem) {
                                return elem.label;
                            });
 
                            // Make it nice and compute continous days
                            var firstDay = moment(data.records[0][0]);
                            var lastDay = moment(data.records[data.records.length - 1][0]);
                            var days = [];
                            while (firstDay.isSameOrBefore(lastDay)) {
                                days.push(firstDay.toDate());
                                firstDay.add(1, 'd');
                            }
 
                            // Create groups and series from array of records                            
                            // This groups the records by day
                            var hlp = data.records.reduce(function (acc, cur) {
                                var key = moment(cur[0]).toDate();
                                if (acc[key]) {
                                    acc[key][cur[1]] = cur[2];
                                } else {
                                    acc[key] = {};
                                    $.each(artists, function (i, val) {
                                        acc[key][val] = val === cur[1] ? cur[2] : null;
                                    });
                                }
                                return acc;
                            }, {});
 
                            // This collects the items by artists
                            var series = artists.map(function (label) {
                                var data = [];
                                var prev = 0;
                                $.each(days, function (i, value) {
                                    var cur = hlp[value] && hlp[value][label] || prev;
                                    data.push(cur);
                                    prev = cur;
                                });
                                return {name: label, items: data};
                            });
 
                            self.areaGroupsValue(days);
                            self.areaSeriesValue(series);
                            self.dataCursorValue('on');
                        }
                    });
 
 
                    $.when(
                            $.ajax({
                                url: "/api/artists/" + self.selectedArtists().join() + "/topNTracks",
                                type: 'GET',
                                data: dateRange
                            }),
                            $.ajax({
                                url: "/api/artists/" + self.selectedArtists().join() + "/topNAlbums",
                                type: 'GET',
                                data: dateRange
                            })
                    )
                   .done(function (tracks, albums) {
                        var hlp = [];
                        for (var i = 0, len = tracks[0].records.length; i < len; i++) {
                            hlp.push({name: tracks[0].records[i][1], items: [tracks[0].records[i][2]]});
                        }
                        self.topNTracksSeriesValue(hlp);   
                        hlp = [];
                        for (var i = 0, len = albums[0].records.length; i < len; i++) {
                            hlp.push({name: albums[0].records[i][0], items: [albums[0].records[i][1]]});
                        }
                        self.topNAlbumsSeriesValue(hlp);   
                    });
 
 
                };
 
                self.optionChanged = function (event, data) {
                    if ("value" !== data.option) {
                        return;
                    }
                    updateCharts();
                };
            }
            return new artistsContentViewModel();
        });

Notice in the first line how you import Oracle JET modules by the means of RequireJS. The defined function than provides a nested function (artistsContentViewModel()) that creates the actual view model. The view model than is passed to the view.

Interesting stuff to see are the ko.observable which are the data bindings. In this demo I make every HTTP call through the jQuery api. There are probably better ways for tables, lists and such, have a look at those scripts, they use the oj.Collection api for the cool table component to achieve the same without the dirty details.

Coming back to my example. The model fields areaSeriesValue and areaGroupsValue go directly into a snippet that I basically copy and pasted from Line with Area Chart component:

<h2>Cumulative plays per artist and day</h2>
<div id='chart-container'>
    <div id="lineAreaChart" style="max-width:1024px;width:100%;height:320px;" data-bind="ojComponent: {
        component: 'ojChart', 
        type: 'lineWithArea', 
        series: areaSeriesValue, 
        groups: areaGroupsValue, 
        timeAxisType: 'enabled',
        animationOnDisplay: 'on',
        animationOnDataChange: 'on',            
        stack: 'on',             
        hoverBehavior: 'dim',
        zoomAndScroll: 'live',
        overview: {rendered: 'off'},
        dataCursor: dataCursorValue
     }"></div>                  
</div>

This may not be fancy, but it does several things pretty well: It’s accessible, fully translated and easy understandable on the user side and easy enough to implement on developer side.

The cookbook

The Cookbook is really valuable. It presents all the components in great detail, the links to the api are up to date and it even gives you hints on where and when to use a certain type of visualization. With it at hand I created the frontend for DOAG2016 in about three days:



Verdict

If you want to be always bleeding edge – which I can fully understand – don’t go near Oracle JET. You won’t like it. If you have to suit a projects needs, presenting lots of data, often visualized and don’t have time or the will to figure all the ways you can setup a JavaScript application yourself, give OracleJET a try.

I find the basic architecture well thought through, highly extensible (I did it with several Spring collections apis and more) and excellent documented.

One of the best things is, from a Java developers perspective actually, is the fact, that it doesn’t want to hide JavaScript and HTML code and fragments behind Java code, which brings in too much abstraction according to my experience. You can achieve a lot by using for example GWT based stuff, but the moment you have to create your own components, you basically have to learn the interns of the chosen framework, JavaScript, HTML and CSS… The later 3 are somewhat standards, which is why I like to have them in my toolbelt anyway.

Summary

In 5 posts I walked you from setting up a skeleton Spring Boot project that provides a database connection or connection pool and a jOOQ context to creating an Oracle Database inside a container for developing and integration purposes to advanced analytic queries and in the end, showed one way to provide a UI. After 5 posts we end with a decent looking, database centric but not database dependent web applications.

In all steps I opted for the tools that make my life as a developer easier, facilitate the features I already payed for and help my customer to achieve their business goals.

There are several possible deployment scenarios: Run the application on Pivotal CF, get yourself a PostgreSQL database from the marketplace. You just have to push it. Put your frontend on some CDN. Or also on CF with the static build pack.

If you need an Oracle database, maybe Amazon RDS is the right choice for you. It doesn’t take much effort to run a Spring Boot application on Amazon EC2.

Do you prefer getting your Oracle Database right from the vendor? I once was in a talk by both Bruno and Josh who deployed a Spring Boot application to the Oracle Cloud.

Regarding your database: I still love coding in Java. Even more so with Java 8. But why not using parts of all the awesome analytic functions my database, for example PostgreSQL and Oracle, offer? Both support fantastic spatial queries, XML and JSON. Maybe you already have relational database knowledge in your company: Use it! Get rid of bad practices putting everything into the database, but use it for what it was designed for. Don’t reinvent the wheel.

Last but not least: If you have the time and ambition, try out new features (not only in the front end). Implement stuff yourself. It’s fine. Learn. But if you have a project goal, maybe a prepackaged structure for a client side web application is enough and something like OracleJET is of value to you as well.

Thank you so much for your attention and reading so far. The demo project and the talk have been in the making for about 6 months. We actually use most of it inside new projects (not the OracleJET part yet) and it was time well invested researching that stack.

| Comments (5) »

14-Nov-16