Thursday, 29 April 2021

Jelastic CLI

Just some notes of mine on how to install Jelastic command line tools and how to connect to your Jelastic provider1 2.

A little disappointed that installing the command line tools doesn't let me know that it "succeeded". It just returns my command prompt, with no indication what it did.

I thought it had quit unexpectedly.

The first call to the API will require authentication.

As I have enabled two-factor authentication, it's best if I create a personal access token3.

Success!

The absolute main reason to use it, I think, is the ability to move my static IP address of a Jelastic Node to another Node4, creating seamless upgrades.

I've tried it, and it's awesome.

I don't even have to explain how it works here. It's simple and the guide is fine.

References

[1] Payara platform and Jelastic PAAS
[2] Jelastic - Jelastic CLI Overview
https://docs.jelastic.com/cli/
[3] Jelastic - Personal Access Tokens
https://docs.jelastic.com/personal-access-tokens/
[4] Jelastic - CLI Tutorial: Public IPs (External Addresses) Swap
https://docs.jelastic.com/cli-ip-swap/

Thursday, 22 April 2021

Alternate Docroots

I have a pressing need to allow files to be accessed that are static.

Unfortunately, there's a web application sitting on my root context ("/").

So I need to define alternate docroots1.

Unfortunately, this seems to be a specific Glassfish or Payara configuration.

As it is bad form, to put this in my code base (who knows where my wars will end up someday), it's better if I put it in the domain.xml file.

That way it's application server dependent, instead of war dependent.

However, I have found the following2:

virtual server's alternate docroots are considered only if a request does not map to any of the web modules deployed on that virtual server. A web module's alternate docroots are considered only once a request has been mapped to that web module.

Which means that an alternative docroot on the virtual server is basically unusable if you have a webapplication situated at your context root "/".

As an example consider the following:

Microprofile Config

Now, I don't much like putting pathnames in my web modules. So I was wondering if it's possible to change that by using Microprofile Config.

And it is3!

It will look something like this:

Other application servers

Other application servers have similar options (of which I know nothing).

In WildFly or the EAP4, it is possible to add another file handler and another location to the undertow subsystem in standalone.xml.

References

[1] A programmer's blog - Map an external directory into Glassfish
http://harkiran-howtos.blogspot.com/2009/08/map-external-directory-into-glassfish.html
[2] Sun GlassFish Enterprise Server v3 Prelude Developer's Guide - Alternate Document Roots
https://docs.oracle.com/cd/E19776-01/820-4496/geqpl/index.html
[3] Payara Community Documentation - Types of variable references
https://docs.payara.fish/community/docs/5.2020.7/documentation/payara-server/server-configuration/var-substitution/types-of-variables.html
[4] StackOverflow - How to configure Wildfly to serve static content (like images)?
https://stackoverflow.com/questions/22684037/how-to-configure-wildfly-to-serve-static-content-like-images

Thursday, 15 April 2021

Learning Kotlin

Well, trying to get to grips with Kotlin, and actually write something with it.

And I have a two day Kotlin course to attend.

I also managed to pick up Programming Kotlin by Venkat Subramanian.

It also helps that I have been pair programming with a Colleague who is already well versed in the language.

References

Blog - My First Kotlin Reference
https://randomthoughtsonjavaprogramming.blogspot.com/2020/06/kotlin.html
Programming Kotlin
enkat Subramanian

Thursday, 8 April 2021

Getting a Native Query Typed in JPA

Recently I tried using a native query to return a result.

This worked fine, except that I had to cast the resulting list to the appropriate list. (which is ugly).

Like so:

List<Room> rooms = (List<Room>) getEntityManager().createNativeQuery(AdminRoom.GET_SEARCH_QUERY)
        .setParameter(1, "%" + description + "%")
        .setMaxResults(pageSize)
        .setFirstResult(offset)
        .getResultList();

I thought I could use the same thing I use daily in my createNamedQuery calls, namely add the appropriate class behind it.

Like so:

List<Room> rooms = (List<Room>) getEntityManager().createNativeQuery(AdminRoom.GET_SEARCH_QUERY, Room.class)...

Unfortunately, the return value of the createNativeQuery method is "Query" which is totally untyped, contrary to "TypedQuery", which I would have liked.

Of course, people have already found this out when I looked it up1.

The API seems to be a little wonky in that area.

References

[1] StackOverflow - entityManager.createNativeQuery does not return a typed result
https://stackoverflow.com/questions/54109546/entitymanager-createnativequery-does-not-return-a-typed-result

Thursday, 1 April 2021

StreamingOutput : streaming large json responses in REST API

So I had to move a large number of database objects into a JSON response, and I was looking for a neat way to do it.

Originally, I already had the idea of having the database generate JSON responses for me. You can find more information on this here1.

But then I thought it would make sense to, instead of loading all those json strings from the database in memory, streaming them to the JSON generator in my REST Service.

It looked quite easy.

Database streaming

Now, I found out that instead of getResultList(), I could use getResultStream(). Unfortunately, the default implementation of getResultStream() just delegates to getResultList(), which doesn't help at all2.

Also, there seems to be a number of other pitfalls to fall into as well2, 3. So, my first attempt displayed here just might be flawed, or might be flawed if you're using something other than MariaDB.

My attempt at a scrolling cursor, instead of just dumping the entire thing in our lap.

Streaming as a REST Service

So I found some information on how to do this at [4].

@GET
@Produces(
{
  "application/json"
})
public Response findAll(@Context UriInfo info)
{
  StreamingOutput stream = StreamerHelper.getStream(getEntityManager(), AdminItem.GET_QUERY);   return Response.ok(stream).build();
}

I think I could use the Fetch way5 on the client side, but in my case it's not needed.

References

[1] Using SQL to generate JSON output
http://randomthoughtsonjavaprogramming.blogspot.com/2020/01/using-sql-to-generate-json-output.html
[2] JPA 2.2’s new getResultStream() method and how you should NOT use it
https://thorben-janssen.com/jpa-2-2s-new-stream-method-and-how-you-should-not-use-it/
[3] Vlad Mihalcea - Hibernate performance tuning tips
https://vladmihalcea.com/hibernate-performance-tuning-tips/
[4] Response streaming between JAX-RS and Web-Components (Part 1)
https://schoeffm.github.io/posts/response-streaming-between-jaxrs-and-webcomponents-part1/
[5] Response streaming between JAX-RS and Web-Components (Part 2)
https://schoeffm.github.io/posts/response-streaming-between-jaxrs-and-webcomponents-part2/