Tuesday 22 December 2020

Notes on Unity

So I decided to try some game programming in Unity1.

Since it's all new to me, I'd thought I'd write some notes here, to remember how I did some things.

Skybox

add here how to add a skybox

Movement

also navigation

References

[1] Wikipedia - Unity
https://en.wikipedia.org/wiki/Unity_(game_engine)

Thursday 17 December 2020

Payara and Jakarta 9

Interesting.

There's a tech preview in the latest Payara 5 application server1, that allows deploying Jakarta EE 9 applications.

The Eclipse Transformer basically auto transforms the classes and resource files back to the old packages, upon deployment.

References

[1] Payara - Eclipse Transformer Configuration Option with Jakarta 9 Milestone Release
https://blog.payara.fish/eclipse-transformer-configuration

Thursday 10 December 2020

The Three options with Optional

There are basically three ways to deal with an optional, when receiving one.

  1. throw an exception if the optional is empty, because it's a faulty situation. (.orElseThrow)
  2. do not do anything, but proceed with the next step. (.ifPresent(dosomething))
  3. provide a default value. (.orElse(default))

I'm writing it down here, because each of these three cases is highly dependent on context.

And I've noticed in my work that I have a tendency to take option 2, even though it might be considered an error.

Thursday 3 December 2020

Finding the index of an element in a List using Streams

So, I recently had a need to find out the index of an element in a List.

I could take the traditional approach, and use a for loop.

But I was wondering if I could use Streams, and if I could, would that be "better" (for some vague notion of "Better").

Any comments on what you would prefer, and why?

References

Baeldung - How to Iterate Over a Stream With Indices
https://www.baeldung.com/java-stream-indices

Thursday 26 November 2020

Why aren't Java Collections remove methods generic?

I recently came across a small problem. The program ran fine, but my IDE had it underlined as being highly dodgy.

It is the same for Collection.contains and Map.get

Just see the references why this is.

References

StackOverflow - Why aren't Java Collections remove methods generic?
https://stackoverflow.com/questions/104799/why-arent-java-collections-remove-methods-generic
Youtube - Advanced Topics in Programming Languages: Java Puzzlers,...
https://www.youtube.com/watch?v=wDN_EYUvUq0

Thursday 15 October 2020

Running Java in the Cloud - Jelastic

So I decided to try running some of my stuff in the cloud, instead of having to hire a Virtual Machine type thing.

In order to have to limit my changes, I decided to go with Jelastic1.

I decided to try out hosting provider EAPPS2, because they are one of the providers of PaaS3 with Jelastic4.

They suggested I'd read up on [5].

Some requirements I'd like:

  1. must support Let's Encrypt certificates
  2. access to the filesystem would be nice (I'm keeping logfiles)
  3. A Mysql/MariaDB database is a must
  4. Need to be able to upload an existing database
  5. Easily create backups.
  6. Must support websockets
  7. Support DNS for custom domains.

It supports all of those, and relieves me of some server administration and maintenance.

References

[1] Jelastic
https://jelastic.com/
[2] EAPPS HOSTING - Leading Managed Hosting Provider
https://www.eapps.com/
[4] eApps PaaS, Powered by Jelastic
https://www.eapps.com/platforms/paas.php
[3] Wikipedia - PaaS
https://en.wikipedia.org/wiki/Platform_as_a_service
[5] Getting Started with eApps Platform as a Service (PaaS)
https://support.eapps.com/index.php?/Knowledgebase/Article/View/535/79/getting-started-with-eapps-paas-platform-as-a-service
Jelastic Blog - JDBC Connection Pool for GlassFish and Payara Java Application Servers
https://jelastic.com/blog/jdbc-connection-pool-java-glassfish-payara/
Jelastic Blog - Free Let’s Encrypt SSL Certificates: Out-of-Box Integration with the Most Popular Software Stacks
https://jelastic.com/blog/free-ssl-certificates-with-lets-encrypt/
Jelastic - Import and Export Dump Files to MySQL/MariaDB
https://docs.jelastic.com/dump-import-export-to-mysql/
Jelastic - Storing Data in Local Filesystem
https://docs.jelastic.com/local-filesystem-storage/
DockerHub - jelastic/payara
https://hub.docker.com/r/jelastic/payara/
Jelastic - Sending e-mail from your jelastic environment
https://support.eapps.com/index.php?/Knowledgebase/Article/View/535/79/getting-started-with-eapps-paas-platform-as-a-service#sending-e-mail-from-your-jelastic-environment
Jelastic Developers Center - WebSockets Support for Java
https://docs.jelastic.com/websockets-java/
Jelastic Developers Center - Custom Domain Name
https://docs.jelastic.com/custom-domains/

Friday 11 September 2020

My Angular App

Download nodejs from nodejs.org

Unpack nodejs

Install nodejs (and NPM to go with it automatically) locally.

$ ln -s node-v14.9.0-darwin-x64 nodejs

Add "export PATH=/Users/mrbear/nodejs/bin:$PATH" to .bashrc

Install Angular CLI1.

$ npm install -g @angular/cli
[angular@vps386 ~]$ ng --version
     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/
    

Angular CLI: 10.0.8
Node: 14.9.0
OS: darwin x64

Angular:
...
Ivy Workspace:

Package Version
------------------------------------------------------
@angular-devkit/architect 0.1000.8
@angular-devkit/core 10.0.8
@angular-devkit/schematics 10.0.8
@schematics/angular 10.0.8
@schematics/update 0.1000.8
rxjs 6.5.5

Update angular CLI

npm search @angular/cli

Initial project creation

[angular@vps386 ~]% ng new myproject
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS
CREATE myproject/README.md (1027 bytes)
CREATE myproject/.editorconfig (274 bytes)
CREATE myproject/.gitignore (631 bytes)
CREATE myproject/angular.json (3590 bytes)
CREATE myproject/package.json (1261 bytes)
CREATE myproject/tsconfig.base.json (458 bytes)
CREATE myproject/tsconfig.json (426 bytes)
CREATE myproject/tslint.json (3184 bytes)
CREATE myproject/.browserslistrc (853 bytes)
CREATE myproject/karma.conf.js (1021 bytes)
CREATE myproject/tsconfig.app.json (292 bytes)
CREATE myproject/tsconfig.spec.json (338 bytes)
CREATE myproject/src/favicon.ico (948 bytes)
CREATE myproject/src/index.html (295 bytes)
CREATE myproject/src/main.ts (372 bytes)
CREATE myproject/src/polyfills.ts (2835 bytes)
CREATE myproject/src/styles.css (80 bytes)
CREATE myproject/src/test.ts (753 bytes)
CREATE myproject/src/assets/.gitkeep (0 bytes)
CREATE myproject/src/environments/environment.prod.ts (51 bytes)
CREATE myproject/src/environments/environment.ts (662 bytes)
CREATE myproject/src/app/app-routing.module.ts (245 bytes)
CREATE myproject/src/app/app.module.ts (393 bytes)
CREATE myproject/src/app/app.component.css (0 bytes)
CREATE myproject/src/app/app.component.html (25757 bytes)
CREATE myproject/src/app/app.component.spec.ts (1068 bytes)
CREATE myproject/src/app/app.component.ts (213 bytes)
CREATE myproject/e2e/protractor.conf.js (869 bytes)
CREATE myproject/e2e/tsconfig.json (299 bytes)
CREATE myproject/e2e/src/app.e2e-spec.ts (642 bytes)
CREATE myproject/e2e/src/app.po.ts (301 bytes)
✔ Packages installed successfully.
Successfully initialized git.
[angular@vps386 ~]$ % ng serve
Compiling @angular/core : es2015 as esm2015
Compiling @angular/animations : es2015 as esm2015
Compiling @angular/compiler/testing : es2015 as esm2015
Compiling @angular/animations/browser : es2015 as esm2015
Compiling @angular/core/testing : es2015 as esm2015
Compiling @angular/common : es2015 as esm2015
Compiling @angular/platform-browser : es2015 as esm2015
Compiling @angular/common/http : es2015 as esm2015
Compiling @angular/animations/browser/testing : es2015 as esm2015
Compiling @angular/common/testing : es2015 as esm2015
Compiling @angular/router : es2015 as esm2015
Compiling @angular/forms : es2015 as esm2015
Compiling @angular/platform-browser/testing : es2015 as esm2015
Compiling @angular/platform-browser/animations : es2015 as esm2015
Compiling @angular/platform-browser-dynamic : es2015 as esm2015
Compiling @angular/common/http/testing : es2015 as esm2015
Compiling @angular/platform-browser-dynamic/testing : es2015 as esm2015
Compiling @angular/router/testing : es2015 as esm2015

chunk {main} main.js, main.js.map (main) 60.6 kB [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 141 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.15 kB [entry] [rendered]
chunk {styles} styles.js, styles.js.map (styles) 12.4 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 2.66 MB [initial] [rendered]
Date: 2020-09-02T12:23:53.701Z - Hash: c7223a73cc964c3ed1e6 - Time: 5305ms
** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
: Compiled successfully.

Creating our first component

[angular@vps386 ~]$ ng generate component player-settings
installing component
create src/app/player-settings/player-settings.component.css
create src/app/player-settings/player-settings.component.html
create src/app/player-settings/player-settings.component.spec.ts
create src/app/player-settings/player-settings.component.ts
update src/app/app.module.ts

Components, Directives, Pipes and Services

For an indepth explanation see reference [4].
modules
a grouping of different components and services
components
a component controls a patch of screen called a view
directives
Attribute or structural directives change the Dom. For example ngIf and ngFor. A component is basically a specialized form of directive.
pipes
filters, for example for displaying dates and currency which are built in filters.
services
independent business logic or connections to external sources wrapped in classes and injected.

Verifying Angular Version

The version of angular can be seen in the dom of your app, something like:
<app-root _nghost-jcv-c16="" ng-version="10.0.14">

Settings depending on environment (prod/test/dev)

There are different .ts files loaded depending on which environment you are building for. These are appropriately named environmnent.*.ts.

See for more information references 2 and 3.

Deploy

ng build --target=production --base-href '/myapp/'

References

[1] Github - Angular CLI
https://github.com/angular/angular-cli
[2] StackOverflow - How to config different development environment in angular 2 app
http://stackoverflow.com/questions/36004810/how-to-config-different-development-environment-in-angular-2-app
[3] Shayne Boywer: Angular CLI using the environment option
http://tattoocoder.com/angular-cli-using-the-environment-option/
[4] Angular 2 - Architecture
https://angular.io/docs/ts/latest/guide/architecture.html
Thoughtram - Understanding @Injectable in Angular
https://blog.thoughtram.io/angular/2015/09/17/resolve-service-dependencies-in-angular-2.html

Thursday 10 September 2020

How to Tell Time in Java’s Garbage Collection

I found this interesting article1 on clock drifts and hardware clocks and OS clocks and Java and logging.

I really liked the quote in there:

“A person with a watch knows what time it is. A person with two watches is never sure.”
- Segal's Law

References

[1] How to Tell Time in Java’s Garbage Collection
https://devblogs.microsoft.com/java/how-to-tell-time-in-javas-garbage-collection/

Wednesday 2 September 2020

Creating a global .gitignore file

It's possible to create a global .gitignore file1 that is automatically shared among all your repositories.

Why should I do this in the first place? Well, there are a couple of reasons.

One example is of course, I want the same rules to apply to all my repositories.

But, in my case, at work, we are actually using Subversion and not Git. But I do use Git.

And I do not want to pollute the entire Subversion repository with my .gitignore files.

So for me, this is a valid solution.

Let's check that I do not already have this configuration setting active:

git config --list
user.name=Mr. Bear
user.email=mrbear@bears.com
svn.rmdir=true
alias.co=checkout
core.excludesfile=/home/mrbear/.gitignore_global
core.autocrlf=input
core.ignorecase=false

You'll notice that among my properties, I already have a core.excludesfile=/home/mrbear/.gitignore_global.

I added it as follows:

$ git config --global core.excludesfile ~/.gitignore_global

Than just populate it like you do with any .gitignore file.

References

[1] Docs github.com - Configuring ignored files for all repositories on your computer
https://docs.github.com/en/github/using-git/ignoring-files#create-a-global-gitignore

Monday 24 August 2020

Kind of Problems

Smashed watch
There are so many issues at once that fixing one has no benefit unless you fix others too.
Leaky Pipe
Fixing one problem causes the others to intensify. If you plug up one leak in a pipe leaking in multiple places, that increases the water pressure causing the other spots to leak more.
Shark Laser
A proposed solution is not aiming at a meaningfully important problem, so it doesn’t matter how well you get it to work or how much you enhance it.
Oil Land
A big problem is so close to being solved that the benefits will accrue to whoever first bothers to put a little effort into it.
Lead to Gold
A problem is so hard that humans aren’t even close to being smart enough or technologically advanced enough to being able to solve it. We toil away pointlessly at trying to solve it.
Booby Trapped Garden
A problem is really hard to solve for reasons that are not at all apparent from the outside, leading to lots of attempts to solve it, all of them miserable failures.
Feature Creep
The problem keeps growing in scope. It cannot be solved because attempts to solve it keep increasing the definition of what the problem is considered to be.
Sleeping Horror
The problem is not that likely to happen, but if it does, it will be horrible. Nobody bothers to try to solve it because they assume it probably won’t happen, and plus, there are more immediately pressing concerns. The horror wakes up eventually.
Middle Court Shot
A problem could be solved pretty easily, but it falls between multiple people’s responsibilities. Hence nobody takes responsiblity for it, assuming someone else will do so.
Will-o'-the-wisp
A problem that nobody can solve because nobody understands what is causing it.
Tug of war
A problem for one group that can’t be solved without making another group substantially worse off.
Piñata
A minor problem or non-existent problem that is promoted as a major problem for political benefit, or so as to distract from harder to solve bigger problems.
Too much salt
A problem that’s created by the solution used to solve another problem.
PlayPump
A problem created by well intentioned do-gooders due to naivety.
Death spiral
One problem created another problem which creates more problems leading to an unsolvable cluster of problems.
Loose Thread
A problem that would have been very easy to solve if it were worked on early isn’t solved because it seems too minor to worry about. It keeps getting worse and worse until it’s very costly to fix.
Sleeping Dog
A potential problem that only actually becomes a problem if you try to solve it.
Hated Equilibrium
A situation where most everyone is unhappy with the state of affairs, but no one can unilaterally make the situation better on their own. The parties can’t find a way to coordinate so that required actions occur simultaneously, so get stuck in the bad state
Moving the Ocean
A significant problem where the cost of solving it is so high that it’s not even worth solving.
Chesterton's Fence
Something that appears to be a problem was actually put there on purpose as the solution to a (now hard to spot) problem, and so is, in fact, not actually problem.
Demonic Problem
A problem that seems like it will wreck you if you make it your job to try to solve it, and you are absolutely correct. Yet for some reason you are tempted to try.
Ship of Theseus
A problem that is not real, and only seems real because of confusion or the complexity required to think about it clearly.
Scylla
A really awful problem whose solution is itself so bad that it’s only barely worth implementing.
Ocean of Pain
A problem so big that you can only hope to solve some tiny part of it, which demotivates people from even trying to do that.
Paper Straw
A problem that is only very slightly important, but it’s socially rewarded to pretend it is much more important than it is. Eventually some people may even forget they are pretending.
Toilet Crusade
A problem that is actually important, but it is so unsexy that almost nobody wants to try to tackle it.
Sophie’s Choice
A problem you are faced with where you will feel you’ve acted unethically or experience remorse no matter which option you choose.
Cursed Treasure
A problem such that whoever solves it will be punished, or suffer severe negative consequences.
Living Mummy
A problem such that, no matter how many times it is solved, it will eventually emerge again.
Drowning Child
A problem that you become morally obligated to try to solve as soon as you encounter it or witness it clearly enough.
Sinking Ship
A hard to solve problem that everyone avoids trying to solve for fear they will get dragged down with the ship (or blamed for it sinking).

References

Problem-Solving Techniques That Work For All Types of Challenges
https://www.spencergreenberg.com/2017/06/1514/

Friday 7 August 2020

Dabbling in Unity

So I decided to try some game programming in Unity1.

Unity is a crossplatform game engine with scripting in C#.

Now, as I cannot design graphical assets to save my life, I decided to buy some off the shelve ones, and free ones, and see how far I can get.

So, this blog post is basically for me, to remember what kind of things I used/needed or might possibly use/need.

Tutorials

ConceptArtEmpire - Best Unity 3D Game Design Tutorials & Video Courses For Beginners
https://conceptartempire.com/unity-3d-tutorials/

Graphical Assets

Unity Asset Store - Nature Starter Kit 2 (free)
https://assetstore.unity.com/packages/3d/environments/nature-starter-kit-2-52977
Unity Asset Store - RPG Medieval Kingdom Kit (see Beffio)
https://assetstore.unity.com/packages/3d/environments/fantasy/rpg-medieval-kingdom-kit-118468
Unity Asset Store - Bitgem (see BitGem)
https://assetstore.unity.com/publishers/1299
Unity Asset Store - Rocks and stones
https://assetstore.unity.com/packages/3d/environments/landscapes/rocks-and-stones-hand-painted-154735
Unity Asset Store - Modular Fantasy Town
https://assetstore.unity.com/packages/3d/environments/fantasy/modular-fantasy-town-90075
Beffio - Game Assets Development by Beffio
https://www.beffio.com/
BitGem - Low Poly 3D Models & Hand Painted Textures for Game Dev
https://shop.bitgem3d.com/
AZURE nature
https://assetstore.unity.com/packages/3d/environments/fantasy/azure-nature-167725

Plugins

Unity Asset Store - DoozyUI: Complete UI Management System
https://assetstore.unity.com/packages/tools/gui/doozyui-complete-ui-management-system-138361
Unity Asset Store - RPG & MMO UI 5
https://assetstore.unity.com/packages/2d/gui/rpg-mmo-ui-5-95223
Cinemachine (free)
https://unity.com/unity/features/editor/art-and-design/cinemachine

References

[1] Wikipedia - Unity
https://en.wikipedia.org/wiki/Unity_(game_engine)

Thursday 30 July 2020

The Merge Statement in SQL

I needed some place to write this down. I don't use it often (or at all) and it has too many advantages for me to ignore it.

Interestically enough, the merge statement sometimes seems to have a huge performance advantage when needing to perform operations in bulk.

But this effect can be absent, when attempting merge statements on individual entries.

MERGE INTO target_table
USING source_table
ON search_condition
    WHEN MATCHED THEN
        UPDATE SET col1 = value1, col2 = value2,...
        WHERE <update_condition>
        [DELETE WHERE <delete_condition>]
    WHEN NOT MATCHED THEN
        INSERT (col1,col2,...)
        values(value1,value2,...)
        WHERE >insert_condition>;
MERGE INTO items gemc
USING (select orderid from orders where customer=5300) geme
ON (gemc.orderid = geme.orderid and gemc.articlenr = 120)
WHEN MATCHED THEN
    UPDATE SET gemc.coupon = 'AFEY12',
               gemc.amount = gemc.amount + 1
    WHERE gemc.orderid = geme.orderid
    AND gemc.articlenr = 120
WHEN NOT MATCHED THEN
    INSERT(gemc.itemid, gemc.orderid, gemc.articleid, gemc.coupon, gemc.amount, gemc.creation)
    VALUES(seq_items.nextval, geme.orderid, 120, 'AFEY12', 1, sysdate);

References

Wikipedia - Merge(SQL)
https://en.wikipedia.org/wiki/Merge_(SQL)
Oracle Tutorial - Oracle Merge
https://www.oracletutorial.com/oracle-basics/oracle-merge/

Thursday 23 July 2020

Linus Torvals on Debuggers

I happen to come across this priceless piece of text1 from Linus Torvals, that I feel should have a mention here.

References

[1] lwn.net - Re: Availability of kdb
https://lwn.net/2000/0914/a/lt-debugger.php3

Thursday 16 July 2020

AssertJ and how your IDE can help

So I am using AssertJ1 to verify results of my Unit Tests.

I also (after the advice of a colleague) installed a Plugin into my IntelliJ IDEA called Concise AssertJ Optimizing Nitpicker ​(Cajon)​2

So I needed to verify the equivalence of an object. I wanted to make sure it was the exact same object I was expecting.

In my naivite I tried something like this.

assertThat(getItems()).hasSize(1);
Optional<Item> first = CollectionUtilities.getFirst(getItems());
assertThat(first).isPresent();
assertThat(first.get() == originalitem).isTrue();

My IDE complained that "Moving binary expression out of assertThat() would be more meaningful".

I completely agreed with that.

assertThat(getItems()).hasSize(1);
Optional<Item> first = CollectionUtilities.getFirst(getItems());
assertThat(first).isPresent();
assertThat(first.get()).isSameAs(originalitem);

Then my IDE commplained that "Moving get() expression out of assertThat() would be more concise", which of course is obvious.

assertThat(getItems()).hasSize(1);
Optional<Item> first = CollectionUtilities.getFirst(getItems());
assertThat(first).isPresent();
assertThat(first).containsSame(originalitem);

Then, of course, Multiple assertThat() statements can be joined together

assertThat(getItems()).hasSize(1);
Optional<Item> first = CollectionUtilities.getFirst(getItems());
assertThat(first).isPresent().containsSame(originalitem);

Which means that Implicit isPresent() assertion is covered by containsSame()

assertThat(getItems()).hasSize(1);
Optional<Item> first = CollectionUtilities.getFirst(getItems());
assertThat(first).containsSame(originalitem);

And that's what I ended up with.

Truly, sometimes my IDE has some good ideas.

Alternative

Of course, there are easier methods, but I wanted to verify that it is the exact same instance.

Otherwise, I could have simply done something like:

assertThat(getItems()).containsExactly(originalitem);

Still not entirely sure that this is not better, despite not an exact match check.

References

[1] AssertJ
https://assertj.github.io/doc/
[2] Concise AssertJ Optimizing Nitpicker ​(Cajon)​
https://plugins.jetbrains.com/plugin/12195-concise-assertj-optimizing-nitpicker-cajon-/

Thursday 9 July 2020

Background : How we got the generics we have

So I came across this text1 on the background of the Generics in the Java Platform.

And I thought it worth my while to put it in here in my blog for easy reference.

References

[1] Brian Goetz - Background : How we got the generics we have
https://cr.openjdk.java.net/~briangoetz/valhalla/erasure.html

Monday 29 June 2020

AssertJ SoftAssertions JavaDoc

I recently came across a great example of JavaDoc. It was regarding the AssertJ SoftAssertions class.

It's in the references1.

In short, we have a dinner party hosted at a mansion.

And we're going to use a UnitTest with Assertions to determine if one of the guests has been murdered and who dun it.

It made me smile.

References

[1] SoftAssertions - AssertJ fluent assertions 3.16.1 API
https://www.javadoc.io/doc/org.assertj/assertj-core/latest/org/assertj/core/api/SoftAssertions.html

Thursday 18 June 2020

Kotlin

I am busy trying to learn Kotlin.

It's important as my company decided to accept the use of Kotlin for new development.

As a matter of fact, I'm currently implementing an API with a colleague and he already started creating it in Kotlin.

So I'm kinda having to play catchup.

Time to get to work!

References

Kotlin Language Guide
https://kotlinlang.org/docs/reference/
Kotlin Koans
https://kotlinlang.org/docs/tutorials/koans.html

Thursday 11 June 2020

What I learned about Java from my 5-year old.

So, you're at home all day, because of all the COVID stuff, and in order to stay sane, you sometimes have to do things that are out of the ordinary.

Below is my attempt.


Thursday 4 June 2020

The Dangers of Doubles

The problems with Doubles and Floats are already well documented, but sometimes we fall into the trap again.

In short, the representation of a real number1 in Float and Double is not precise2.

Normally, I am well aware of this limitation, but sometimes I get tripped up by already receiving Doubles and Floats as input.

In this case, it involved Geometrie coordinates, in doubles of course.

The following Unit Test shows the problem:

References

[1] Wikipedia - Real number
https://en.wikipedia.org/wiki/Real_number
[2] What Every Programmer Should Know About Floating-Point Arithmetic
https://floating-point-gui.de/

Friday 29 May 2020

Adding MariaDB JDBC Connector to Paraya 5 - Followup

Just decided to do a followup on Adding MariaDB JDBC Connector to Payara 51.

I wanted to see if it was possibly very easy to do this using the command line.

Installing a MariaDB driver

$ ./asadmin add-library /home/mrbear/software/mariadb-java-client-2.3.0.jar
Command add-library executed successfully.

Creating a new JDBC Connection pool

The syntax:

Usage: asadmin [asadmin-utility-options] create-jdbc-connection-pool
        [--datasourceclassname ] [--restype ]
        [--steadypoolsize ]
        [--maxpoolsize ]
        [--maxwait ]
        [--poolresize ]
        [--idletimeout ] [--initsql ]
        [--isolationlevel ]
        [--isisolationguaranteed[=]]
        [--isconnectvalidatereq[=]]
        [--validationmethod ]
        [--validationtable ]
        [--failconnection[=]]
        [--allownoncomponentcallers[=]]
        [--nontransactionalconnections[=]]
        [--validateatmostonceperiod ]
        [--leaktimeout ]
        [--leakreclaim[=]]
        [--creationretryattempts ]
        [--creationretryinterval ]
        [--sqltracelisteners ]
        [--statementtimeout ]
        [--statementleaktimeout ]
        [--statementleakreclaim[=]]
        [--lazyconnectionenlistment[=]]
        [--lazyconnectionassociation[=]]
        [--associatewiththread[=]]
        [--driverclassname ]
        [--matchconnections[=]]
        [--maxconnectionusagecount ]
        [--ping[=]] [--pooling[=]]
        [--statementcachesize ]
        [--validationclassname ]
        [--wrapjdbcobjects[=]]
        [--description ] [--property ]
        [-?|--help[=]] jdbc_connection_pool_id

Note the following:

  • The escape character backslash (\) is used in the --property option to distinguish the semicolon (;).
  • Two backslashes (\\) are used to distinguish the equal sign (=).
  • Two backslashes (\\) are used to distinguish the colon (:).
./asadmin create-jdbc-connection-pool --driverclassname org.mariadb.jdbc.Driver --restype java.sql.Driver --property databaseName=mmud:password=topsecretpassword:user=root:URL=jdbc\\:mariadb\\://localhost\\:3306/mmud:serverName=localhost mmudpool

Let's test it!

./asadmin ping-connection-pool mmudpool

In case you wish to delete it, try:

./asadmin delete-jdbc-connection-pool mmudpool

Creating the JNDI

./asadmin create-jdbc-resource --connectionpoolid mmudpool jdbc/mmud

References

[1] Adding MariaDB JDBC Connector to Payara 5

https://randomthoughtsonjavaprogramming.blogspot.com/2018/12/adding-mariadb-jdbc-connector-to-paraya.html
[2] Payara Blog - An intro to connection pools in payar server 5
https://blog.payara.fish/an-intro-to-connection-pools-in-payara-server-5

Friday 22 May 2020

From JavaEE 8 to JakartaEE 8

So, trying to transition my little hobby project from Java EE to Jakarta EE.

It seems to be going well, mostly because the only thing that has changed are the names of the Maven dependencies1. (for now)

So for now the only changes take place in the pom.xml files.

Here are the changes:

<dependency>
  <groupId>javax</groupId>
  <artifactId>javaee-api</artifactId>
  <version>${javaee.version}</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>jakarta.platform</groupId>
  <artifactId>jakarta.jakartaee-api</artifactId>
  <version>${jakartaee.version}</version>
  <scope>provided</scope>
</dependency>

I did notice that I could remove one Java EE spec in one of my Maven modules. The servlet-spec. Perhaps because I am using something special in there that's included in the default by now?

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

Superfluous stuff

Noticed some stuff I no longer need. Probable leftovers from early days.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.6</version>
    <executions>
        <execution>
            <phase>validate</phase>
            <goals>
                <goal>copy</goal>
            </goals>
            <configuration>
                <outputDirectory>${endorsed.dir}</outputDirectory>
                <silent>true</silent>
                <artifactItems>
                    <artifactItem>
                        <groupId>javax</groupId>
                        <artifactId>javaee-endorsed-api</artifactId>
                        <version>7.0</version>
                        <type>jar</type>
                    </artifactItem>
                </artifactItems>
            </configuration>
        </execution>
    </executions>
</plugin>

Versions

So my versions have changed as follows:

The old:

<javaee.version>8.0.1</javaee.version>

The new:

<jakartaee.version>8.0.0</jakartaee.version>

That seems to be all.

References

[1] Java Magazine - Transition from Java EE to Jakarta EE
https://blogs.oracle.com/javamagazine/transition-from-java-ee-to-jakarta-ee
Rieckpil - Bootstrap your first Jakarta EE 8 application
https://rieckpil.de/howto-bootstrap-your-first-jakarta-ee-8-application/
Jakarta EE - Jakarta EE Compatible Products
https://jakarta.ee/compatibility/

Thursday 14 May 2020

How to Debug a Cake

So, I've been baking cakes for a long time. I got the recipe from my mum, who has also been baking cakes for a long time.

This recipe is basically flower, eggs, butter, bakingpowder, and lots of sugar. You know, the old fashioned way.

Well, a couple of years ago, suddenly my cakes started failing mysteriously.

So I started trying to fix this, by changing stuff randomly. I started downloading recipes from the Internet, to see if they worked better. I bought a cake-flour package from the supermarket, perhaps that worked. I even changed ovens.

None of these things worked.

So, I sat down, and thought about it. And then I realised, I didn't try and find the problem as I would have if I looked at the problem as a bloody Software Designer (which is what I am).

Well, debugging a cake turns out to be hard. System.out.println or logging or breakpoints are quite impossible.

As they say, you have to find the problem during actual production.

Some conclusions

If you did not make any changes to your recipe, and suddenly your cakes start to fail, either one of your ingredients has changed or your process/tools for making the cake. This is an obvious conclusion.

I was going to assume that my tools and process were more or less the same.


The only thing that really works, is to change one ingredient at a time.


In other words:

“How often have I said to you that when you have eliminated the impossible, whatever remains, however improbable, must be the truth? ”- Sherlock Holmes, The Sign of the Four (1890)

It also helps to understand the process. What kind of ingredients in a cake are essential and what kind of role do they play?

Addendum

Well, after a lot of experimenting, and, quite frankly, a lot of dismal ruined cakes, I found the cause to be the butter.

The butter I used, Blue Band, must have changed at the time. So I did a little digging.

I noticed that there are no longer any dairy products in this butter.

And when I use butter made from dairy products, the cakes turn out fine.

Also, when I started checking the supermarket, I did notice that Blue Band also (at around the same time) came out with a new product called "Butter for cookies and cake". I checked, and it did indeed contain dairy products.

Am I just being paranoid in thinking this is not a coincidence?

Tuesday 5 May 2020

Upgrading to Angular 9

I've used the guide in [1].

Just writing down my notes on what I encountered.

$ ng version

Angular CLI: 8.3.23
Node: 10.13.0
OS: linux x64
Angular: 8.2.14
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.803.23
@angular-devkit/build-angular     0.803.23
@angular-devkit/build-optimizer   0.803.23
@angular-devkit/build-webpack     0.803.23
@angular-devkit/core              8.3.23
@angular-devkit/schematics        8.3.23
@angular/cli                      8.3.23
@ngtools/webpack                  8.3.23
@schematics/angular               8.3.23
@schematics/update                0.803.23
rxjs                              6.4.0
typescript                        3.4.5
webpack                           4.39.2

So let's try to update using [2].

Update to the latest 8 version.

ng update @angular/core@8 @angular/cli@8

This upgraded my version of Angular from 8.3.23 to 8.3.26

Update to the 9 version.

ng update @angular/core @angular/cli

This upgraded my version from 8.3.26 (obviously) to 9.1.3 .

Of course, this means it's probably a good idea to upgrade to the lastest libraries I also use.

npm install npm@latest -g
npm upgrade

These are (in no particular order):

  • ckeditor (1.1.2 to 1.2.3)
  • @ng-bootstrap/ng-bootstrap (5.1.5 to 6.1.0)
  • ngx-cookie-service (2.3.0 to 2.4.0)

I've removed jquery and popper.js, these are no longer necessary as I am using ng-bootstrap.

References

[1] Upgrade Angular 8/7 to Angular 9 With Ng Update & Angular CLI v9
https://www.techiediaries.com/angular/upgrade-angular-8-7-to-angular-9-with-cli-ng-update/
[2] Official Angular Updater Tool on the Web
https://update.angular.io/

Wednesday 29 April 2020

Upgrading Fedora Core

There's an article [1] here. I thought I'd bookmark it, for easy reference.

Reference

[1] Fedora Magazine - Upgrading Fedora 31 to Fedora 32
https://fedoramagazine.org/upgrading-fedora-31-to-fedora-32/

Thursday 23 April 2020

Keyboard problems in Linux with IntelliJ

Numpad arrow keys

So the numpad arrow keys do not work in my IntelliJ editor under Fedora Core 31.

I read about similar issues on the Internet.

One of the solutions that worked for me, was to change the file /usr/share/X11/xkb/symbols/keypad.

First off copying the original file seems like a good idea, something like keypad.original.

Then replace all occurrences of KP_Up, KP_Down, KP_Left, KP_Right with Up, Down, Left, Right respectively.

Either rebooting or executing a setxkbmap should do the trick.

Ctrl-Alt-Left and Ctrl-Alt-Right

I use these to go to the next or previous call in Intellij. Linux just wants to switch Workspaces, when I do that.

The shortcuts could not be found using the standard Settings tool.

But I found a solution at [2].

gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-up []
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-down []
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left []
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-right []

With a reset if I decide to need it like:

gsettings reset org.gnome.desktop.wm.keybindings switch-to-workspace-up
gsettings reset org.gnome.desktop.wm.keybindings switch-to-workspace-down
gsettings reset org.gnome.desktop.wm.keybindings switch-to-workspace-left
gsettings reset org.gnome.desktop.wm.keybindings switch-to-workspace-right

References

Medium.com - A simple, humble but comprehensive guide to XKB for linux
https://medium.com/@damko/a-simple-humble-but-comprehensive-guide-to-xkb-for-linux-6f1ad5e13450
[2] Ubuntu - How to disable the keyboard shortcut to switch between workspaces
https://askubuntu.com/questions/744214/how-to-disable-the-keyboard-shortcut-to-switch-between-workspaces

Tuesday 14 April 2020

Backup & Restore of Mariadb Server

Hello, again!

This is just a small blog post on how to backup and restore a MariaDB server, without using MysqlDump, but by directly copying the files in /var/lib/mysql.

Backing up

First of course we need to shutdown mariadb.

# systemctl status mariadb
# systemctl stop mariadb

Copying files:

tar zcvf database_backup_`date +%F`.tgz /var/lib/mysql

Restoring

When putting things back, things start to go wrong1.

Copying the files to a new host, causes this:

2020-04-14 10:45:32 0 [ERROR] InnoDB: Operating system error number 13 in a file operation. 2020-04-14 10:45:32 0 [ERROR] InnoDB: The error means mysqld does not have the access rights to the directory. 2020-04-14 10:45:32 0 [ERROR] InnoDB: os_file_get_status() failed on './ibdata1'. Can't determine file permissions

So, if the below code works, than SELinux is causing the issue:

sudo semanage permissive -a mysqld_t

Now you added mysql_t to permissive, as shown by the below printout:

]# semanage permissive -l

Builtin Permissive Types


Customized Permissive Types

mysqld_t

Turning it back to enforcing, means running:

# semanage permissive -d mysqld_t
libsemanage.semanage_direct_remove_key: Removing last permissive_mysqld_t module (no other permissive_mysqld_t module exists at another priority).

We need to relabel the new /var/lib/mysql directory:

sudo semanage fcontext -a -t mysqld_db_t "/var/lib/mysql(/.*)?"
sudo restorecon -Rv /var/lib/mysql

Checking the current file contexts:

$ ls --directory --context /var/lib/mysql
unconfined_u:object_r:mysqld_db_t:s0 /var/lib/mysql

MariaBackup

I need to check out MariaBackup2 3, as a better solution for creating backups compared to mysqldump.

References

[1] Security-Enhanced Linux with MariaDB
https://mariadb.com/kb/en/selinux/
[2] Backing up and restoring databases
https://mariadb.com/kb/en/backing-up-and-restoring-databases/
[3] MariaBackup
https://mariadb.com/kb/en/mariabackup/
[4] Full Backup and Restore with MariaBackup
https://mariadb.com/kb/en/full-backup-and-restore-with-mariabackup/

Thursday 5 March 2020

On Polish Notation in Software Design

I was looking up Polish Notation, as I remember hearing about it.

And it turns out Polish Notation is actually, basically, when you think about it, exactly how programming languages in my experience work.

For example:

x − 5 6 7

Is polish notation for:

(5 - 6) x 7

This is very very difficult to understand for someone like me who is absolutely not used to Polish Notation.

However, when I write this down in programming language method calls, everything becomes crystal clear immediately.

multiply(minus(5, 6), 7);

For some reason, the statement above makes perfect sense to me.

Likewise as in the Polish Notation, in software design method-calls, the sequence of statements is unambiguous.

With the infix notation, parentheses are required to override operator precedence rules.

Both in Polish Notation as in programming, this does not seem to be required.

References

Wikipedia - Polish notation
https://en.wikipedia.org/wiki/Polish_notation

Thursday 27 February 2020

JavaDoc that makes my head hurt

I found the following javadoc in our source code. It makes my head hurt.

/**
 * Marker interface that marks an executor as a refresh field definitions query executor,
 * i.e. a query executor that refreshes the field definitions.
 */
public interface RefreshFieldDefinitionsQueryExecutor {
}

It repeats the same thing at least three times, twice in the comments and once in the name of the marker interface.

And still I am no closer to understanding what it does.

Thursday 20 February 2020

Spatial Information in an Oracle Database

SDO_GEOMETRY

This is here for me to remember how much magic is used in inserting spatial (geometry) information into an Oracle database1.

CREATE TYPE sdo_geometry AS OBJECT (
SDO_GTYPE NUMBER,
SDO_SRID NUMBER,
SDO_POINT SDO_POINT_TYPE,
SDO_ELEM_INFO SDO_ELEM_INFO_ARRAY,
SDO_ORDINATES SDO_ORDINATE_ARRAY);

A point geometry:

MDSYS.SDO_GEOMETRY(
    2001, -- 2-dimensional (2), non-linear referencing geometry or default (0), point (01)
    28992, -- Amersfoort / RD New
    NULL, 
    MDSYS.SDO_ELEM_INFO_ARRAY(1, 1, 1),
    MDSYS.SDO_ORDINATE_ARRAY(81431.756, 455218.921))

A polygon geometry:

MDSYS.SDO_GEOMETRY(
    2003, -- 2-dimensional (2), non-linear referencing geometry or default (0), polygon (03)
    28992, -- Amersfoort / RD New
    NULL,
    MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1), -- first coordinate (1), exterior (1003), polygon (1)
    MDSYS.SDO_ORDINATE_ARRAY(
        -1041172.16,1407540.16,
        -958596.8,-591471.68,
        1363835.2,-625878.08,
        1319106.88,1428184,
        -1041172.16,1407540.16) -- coordinates
)

A multipolygon geometry:

MDSYS.SDO_GEOMETRY(
    2007, -- 2-dimensional (2), non-linear referencing geometry or default (0), MULTIPOLYGON or MULTISURFACE (07)
    28992, -- Amersfoort / RD New
    NULL, 
    MDSYS.SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1), 
    MDSYS.SDO_ORDINATE_ARRAY(42, 78, 41, 85, 46, 82.7, 45, 79, 42, 78, 43.5, 72.5, 52.5, 72.5, 54.5, 79.5, 79, 60, 93, 46, 53, 32, 54, 25, 49, 22, 45, 17, 41, 16, 37, 23, 33, 24, 25, 20, 33, 46, 39, 53, 43.5, 72.5))

The only thing that makes sense among all the magic numbers are the coordinates. The last coordinate is the same as the first coordinate to close the polygon.

I since have found some more information after some digging regarding the SDO_ELEM_INFO.

It's an array of triplets, where a triplet consists of:

SDO_STARTING_OFFSET
offset within the coordinates array, the first triplet usually has "1" as being the first coordinate in the coordinate array
SDO_ETYPE
type of element
SDO_INTERPRETATION
depends on if SDO_ETYPE is a compound element

I found more information in [2].

WKT - Well-known text representation of geometry

"POLYGON ((194232.738 467652.498, 194232.774322728 467652.19885542, 194232.881179968 467651.917096035, 194232.738 467652.498))"
"POINT (31256.383 393077.6)"
"MULTIPOLYGON(((42 78, 41 85, 46 82.7, 45 79, 42 78),(43.5 72.5, 52.5 72.5, 54.5 79.5, 79 60, 93 46, 53 32, 54 25, 49 22, 45 17, 41 16, 37 23, 33 24, 25 20, 33 46, 39 53, 43.5 72.5)))"

It's possible to create SDO_GEOMETRY in PL/SQL based on WKT strings.

Like so:

SELECT SDO_GEOMETRY('MULTIPOLYGON(((42 78, 41 85, 46 82.7, 45 79, 42 78),(43.5 72.5, 52.5 72.5, 54.5 79.5, 79 60, 93 46, 53 32, 54 25, 49 22, 45 17, 41 16, 37 23, 33 24, 25 20, 33 46, 39 53, 43.5 72.5)))') FROM DUAL;

Convenient if you want to do something quick, but you cannot provide additional information regarding the dimensions, and coordinate system, etc.

Let me rephrase that sentence. It means your resulting geometrie has NO SRID, and you'll get in trouble using it in geometry queries! This is not a joke!

The reverse (if you want to find out the geometrie in WKT format, basically because it reads easier) is of course also possible, like so:

SELECT SDO_UTIL.TO_WKTGEOMETRY(geometry) FROM buildinggeo;

Geometry Functions

So I was playing around with ConvexHull, ConcaveHull and ConcaveHull-Boundary functions.

I took the MultiPolygon in the paragraph above as an example.

SELECT SDO_GEOM.SDO_CONVEXHULL(MDSYS.SDO_GEOMETRY(
2007, -- 2-dimensional (2), non-linear referencing geometry or default (0), multipolygon (07)
28992, -- Amersfoort / RD New
NULL,
MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1,11,2003,1), -- first coordinate (1), Simple polygon whose vertices are connected by straight line segments (1003,1), 11th coordinate (11), Simple polygon whose vertices are connected by straight line segments (1003,1)
MDSYS.SDO_ORDINATE_ARRAY(42, 78, 41, 85, 46, 82.7, 45, 79, 42, 78,
43.5, 72.5, 52.5, 72.5, 54.5, 79.5, 79, 60, 93, 46, 53, 32, 54, 25, 49, 22, 45, 17, 41, 16, 37, 23, 33, 24, 25, 20, 33, 46, 39, 53, 43.5, 72.5) -- coordinates
), 1)
FROM dual;
-- creates MDSYS.SDO_GEOMETRY(2003, 28992, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1, 1003, 1), MDSYS.SDO_ORDINATE_ARRAY(41, 16, 45, 17, 93, 46, 79, 60, 54.5, 79.5, 41, 85, 25, 20, 41, 16))
SELECT SDO_GEOM.SDO_CONCAVEHULL(MDSYS.SDO_GEOMETRY(
2007, -- 2-dimensional (2), non-linear referencing geometry or default (0), multipolygon (07)
28992, -- Amersfoort / RD New
NULL,
MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1,11,2003,1), -- first coordinate (1), Simple polygon whose vertices are connected by straight line segments (1003,1), 11th coordinate (11), Simple polygon whose vertices are connected by straight line segments (1003,1)
MDSYS.SDO_ORDINATE_ARRAY(42, 78, 41, 85, 46, 82.7, 45, 79, 42, 78,
43.5, 72.5, 52.5, 72.5, 54.5, 79.5, 79, 60, 93, 46, 53, 32, 54, 25, 49, 22, 45, 17, 41, 16, 37, 23, 33, 24, 25, 20, 33, 46, 39, 53, 43.5, 72.5) -- coordinates
), 0.1)
FROM dual;
-- creates MDSYS.SDO_GEOMETRY(2003, 28992, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1, 1003, 1), MDSYS.SDO_ORDINATE_ARRAY(41, 85, 42, 78, 43.5, 72.5, 39, 53, 33, 46, 25, 20, 41, 16, 45, 17, 54, 25, 53, 32, 93, 46, 79, 60, 54.5, 79.5, 46, 82.7, 41, 85))
SELECT SDO_GEOM.SDO_CONCAVEHULL_BOUNDARY(MDSYS.SDO_GEOMETRY(
2007, -- 2-dimensional (2), non-linear referencing geometry or default (0), multipolygon (07)
28992, -- Amersfoort / RD New
NULL,
MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1,11,2003,1), -- first coordinate (1), Simple polygon whose vertices are connected by straight line segments (1003,1), 11th coordinate (11), Simple polygon whose vertices are connected by straight line segments (1003,1)
MDSYS.SDO_ORDINATE_ARRAY(42, 78, 41, 85, 46, 82.7, 45, 79, 42, 78,
43.5, 72.5, 52.5, 72.5, 54.5, 79.5, 79, 60, 93, 46, 53, 32, 54, 25, 49, 22, 45, 17, 41, 16, 37, 23, 33, 24, 25, 20, 33, 46, 39, 53, 43.5, 72.5) -- coordinates
), 0.1, 0.01)
FROM dual;
-- creates MDSYS.SDO_GEOMETRY(2003, 28992, NULL, MDSYS.SDO_ELEM_INFO_ARRAY(1, 1003, 1), MDSYS.SDO_ORDINATE_ARRAY(41, 85, 33, 46, 25, 20, 41, 16, 45, 17, 54, 25, 53, 32, 93, 46, 79, 60, 54.5, 79.5, 41, 85))

I will expand on this blog post, as my knowledge in this area is expanded.

References

[1] Spatial and Graph Developer's Guide - 2.2 SDO_GEOMETRY Object Type
https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm#SPATL489
[2] Spatial and Graph Developer's Guide - 2.2.4 SDO_ELEM_INFO
https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm#SPATL494
Spatial and Graph Developer's Guide - 2.1 Simple Example: Inserting, Indexing, and Querying Spatial Data
https://docs.oracle.com/database/121/SPATL/simple-example-inserting-indexing-and-querying-spatial-data.htm#SPATL486

Thursday 13 February 2020

Angular 9.0.0 has arrived!

Wowie! Angular 9 has entered the building!

I am going to be looking long and hard at it and immediately upgrade my existing apps!

References

Version 9 of Angular Now Available — Project Ivy has arrived!
https://blog.angular.io/version-9-of-angular-now-available-project-ivy-has-arrived-23c97b63cfa3
Angular Update Guide | 8.0 -> 9.0 for Basic Apps
https://update.angular.io/#8.0:9.0

Thursday 6 February 2020

On Short Circuit Evaluation

I found the following quote on the Wikipedia page on Short-circuit evaluation1.

The quote is from Edger W. Dijkstra2

The conditional connectives — "cand" and "cor" for short — are ... less innocent than they might seem at first sight. For instance, cor does not distribute over cand: compare

(A cand B) cor C with (A cor C) cand (B cor C);

in the case ¬A ∧ C , the second expression requires B to be defined, the first one does not. Because the conditional connectives thus complicate the formal reasoning about programs, they are better avoided.

— Edsger W. Dijkstra[2]

“There be a lot of long words in there; and I'm naught but a humble pirate3.”

Let's break it down.

(A && B) || C

(A || C) && (B || C)

Possibilities are:

A B C (A && B) || C (A || C) && (B || C)
false false false false false
true false false false false
false true false false false
true true false true true
false false true true true
true false true true true
false true true true true
true true true true true

So, for A = false and C = true,

(false && B) || true -> does not need to evaluate B

(false || true) && (B || true) -> does need to evaluate B.

And this while (A && B) || C == (A || C) && (B || C) holds true.

So that's interesting.

But I fear Edger W. Dijkstra may have been needlessly dogmatic here.

References

[1] Wikipedia - Short-circuit evaluation
https://en.wikipedia.org/wiki/Short-circuit_evaluation
[2] Texas Univerity - Edger W. Dijkstra
http://www.cs.utexas.edu/users/EWD/ewd10xx/EWD1009.PDF
[3] Wikiquote - Pirates of the Caribbean: The Curse of the Black Pearl
https://en.wikiquote.org/wiki/Pirates_of_the_Caribbean:_The_Curse_of_the_Black_Pearl

Thursday 30 January 2020

MariaDB issues

I ran into some issues, and I thought I'd document them here.

Not able to detect platform for vendor name [MariaDB1010.3.17-MariaDB]. Defaulting to [org.eclipse.persistence.platform.database.DatabasePlatform]. The database dialect used may not match with the database you are using. Please explicitly provide a platform using property "eclipselink.target-database".]]

So changed my persistence.xml and added:

<property name="eclipselink.target-database" value="MySQL4"/>

Also:

Local Exception Stack:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.4.payara-p2): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLSyntaxErrorException: (conn=16) Table 'mmud.SEQUENCE' doesn't exist
Error Code: 1146
Call: UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?
       bind => [2 parameters bound]
Query: DataModifyQuery(name="SEQ_GEN_IDENTITY" sql="UPDATE SEQUENCE SET SEQ_COUNT = SEQ_COUNT + ? WHERE SEQ_NAME = ?")
       at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:333)

As the vendor name was not detected, eclipselink switched to a default implementation. The default implementation requires SEQUENCES for the IDENTITY definition.

It turns out the MariaDB implementation of Sequences is not compatible with the standard SQL way of creating sequences.

So I had to add the following property to the JDBC Connection pool:

useMysqlMetadata = true

References

JIRA MariaDB : since 2.4.0 j-connector throws sequence errors via JPA/ eclipselink on @GeneratedValue(strategy = GenerationType.IDENTITY) columns
https://jira.mariadb.org/browse/CONJ-702
Java Persistence API (JPA) Extensions Reference for EclipseLink, Release 2.4 : target-database
https://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/p_target_database.htm
Eclipse JIRA : Bug 462196 - Add support for MariaDB
https://bugs.eclipse.org/bugs/show_bug.cgi?id=462196

Thursday 23 January 2020

Using SQL to generate JSON output

I recently read [1], and it had a very interesting notion.

The idea is to let the database generate JSON, and provide it straight into your client.

So I decided to find out if MariaDB had some support for this as well.

It does2.

So, it basically was nothing more then calling a NativeQuery on the EntityManager, and returning a concatted resultset with a '['prefix and a ']'postfix and a comma-delimiter and away we go.

The native query looked like the following:

It worked flawlessly!

Caveat: of course, this is only in the case where your middleware (as in this example) really doesn't need to do anything with the result.

I mean, you are going to have to do all checks in the database query.

I think this example shows its strength when you just really want to read a lot of data, and do not need to process it.

References

[1] Stop Mapping Stuff in Your Middleware. Use SQL’s XML or JSON Operators Instead
https://blog.jooq.org/2019/11/13/stop-mapping-stuff-in-your-middleware-use-sqls-xml-or-json-operators-instead/
[2] MariaDB - starting with 10.2.3 - JSON Functions
https://mariadb.com/kb/en/library/json-functions/
MariaDB - JSON with MariaDB Platform: What Is JSON and Why Use It – With Examples
https://mariadb.com/resources/blog/json-with-mariadb-10-2/
MariaDB - Relational and Semi-structured Data
https://mariadb.com/database-topics/semi-structured-data/
MariaDB - Function Differences Between MariaDB 10.4 and MySQL 8.0
https://mariadb.com/kb/en/library/function-differences-between-mariadb-104-and-mysql-80/#present-in-mysql-only

Thursday 16 January 2020

Do not use Optional in method parameters

The Java language authors have been quite frank that Optional was intended for use only as a return type, as a way to convey that a method may or may not return a value.

At work there are some cases where providing an Optional as a method parameter is a good idea, because QueryDSL has been configured to automatically return an empty resultset if the optional is not present.

But an Optional as a method parameter seems to be a disputed design choice1.

A lot of Java tooling complains about it (SonarLint, Findbugs, etc).

A lot of people mention that method overloading might be a better and clearer choice.

For example:

I took a stab at it:

Than I had to go and throw up, this is ugly as sin!

The best answer I found on StackOverflow3 without Java 9 so far:

Now this seems very interesting, but they needed to invent something better. And they did. In Java 9.

Optional.ifPresentOrElse​

Perhaps this is why in Java 92 there is a new method in the Optional class called ifPresentOrElse​.

References

[1] StackOverflow - Should Java 8 getters return optional type?
https://stackoverflow.com/questions/26327957/should-java-8-getters-return-optional-type
[2] JavaDoc - Optional (Java SE 9 & JDK 9)
https://docs.oracle.com/javase/9/docs/api/java/util/Optional.html
[3] StackOverflow - Functional style of Java 8's Optional.ifPresent and if-not-Present?
https://stackoverflow.com/questions/23773024/functional-style-of-java-8s-optional-ifpresent-and-if-not-present
IntelliJ Idea Blog - Java 8 Top Tips
https://blog.jetbrains.com/idea/2016/07/java-8-top-tips/
SonarSource rules - "Optional" should not be used for parameters
https://rules.sonarsource.com/java/RSPEC-3553
DZone - Optional Method Parameters
https://dzone.com/articles/optional-method-parameters

Thursday 9 January 2020

The Pitfalls of Boolean Trap

A colleague is looking to update all inspections in IntelliJ at work, which is commendable.

He referred a link, see [1], to me regarding the use of Booleans as method parameters ("switches"), which is a pet peeve of another colleague of mine.

I thought I'd just mention it here, for who's interested.

References

[1] The Pitfalls of Boolean Trap
https://ariya.io/2011/08/hall-of-api-shame-boolean-trap

Thursday 2 January 2020

XMLGregorianCalendar off by a few days on dates before 1582

Oh, darn. Just got bit by this thing.

The customer had stored documents for which it did not know the date with date 01-01-0007.

When importing it via XML, it turned out wrong.

The reference [1] below explains why.

References

[1] StackOverflow - Date change when converting from XMLGregorianCalendar to Calendar
https://stackoverflow.com/questions/16321193/date-change-when-converting-from-xmlgregoriancalendar-to-calendar
Wikipedia - Proleptic Gregorian Calendar
https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar