Posts

  • Extensible Enum Design Pattern

    It’s 2022 already, but still there is a lot of Java code where integers (or strings) are used to represent enums. Like this:

    public static final int COLOR_RED = 1;
    public static final int COLOR_BLUE = 2;
    public static final int COLOR_PURPLE = 3;
    

    This has drawbacks, the most serious is that such values are weakly typed. The compiler has no idea that COLOR_RED and 2*2 represent values from different domains: one represents a color, another one is just some number (maybe, number of beds in an appartment with two bedrooms, each of which has two beds).

  • Instantiating Uninstantiatable

    Let’s imagine that you are writing a Java object serialization framework. You serialized your object (turned it to an array of bytes) and now you need to deserialize it back. To do it, you need to create an empty instance of the class first (this is called ‘instantiation’). How would you do it?

    The most straight-forward and obvious way is to use the no-arg constructor of the class via reflection. Alas, there is a tiny catch: not every class has such a constructor.

    But let’s start from the beginning.

  • Compiling Netty-enabled application with DNS support to native image in 2020

    In 2018, an excellent article was written Instant Netty Startup using GraalVM Native Image Generation that explained how an HTTP server using Netty could be compiled to a Native Image for improved startup time and memory consumption.

    It is 2020 now, the fixes for the problems highlighted by the article are fixed in Netty itself (you can see native-image.properties files in many of its modules). But GraalVM project itself is being actively developed, and, all of a sudden, this can make the compilation fail again if you use netty-dns module with a recent GraalVM version.

    Here, I’m showing what needs to be done to compile an application using Netty as a client, not a server, using its DNS resolver feature.

  • What's the problem with yyyy-MM-dd'T'HH:mm:ss.SSSZ?

    There are many pages in Internet that recommend or mention yyyy-MM-dd'T'HH:mm:ss.SSSZ pattern when dealing with ISO-8601 date-times, for instance Spring documentation https://docs.spring.io/autorepo/docs/spring/4.0.2.RELEASE/javadoc-api/org/springframework/format/annotation/DateTimeFormat.ISO.html and Elasticsearch documentation https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html, to name a couple. But this format is actually troublesome when using ISO-8601 format.

  • Spring reactive transactions atomicity violation

    Spring supports transactions in reactive flows since version 5.2 M2, so this combination (transactivity + reactive streams) is still pretty new. Transactions in imperative mode are here for years, they are well known and no serious caveats are expected. But it turns out that, in the current Spring versions (namely, version 5.2.6), reactive transactions may sometimes violate the atomicity requirement!

  • Localstack Java Lambda Function Execution Caveats

    Localstack is an implementation of AWS cloud stack which makes it very convenient if you want to develop and debug your AWS components locally. Also, it enables the creation of integration tests of your Lambda Functions: you just start Localstack (available as Docker containers, so Testcontainers can be used). Such tests can then be run without a necessity to communicate with real AWS (which would make the tests more fragile, slower and add complexity).

    But it turns out that Localstack’s Lambda Function execution model (at least when it comes to Java functions) is different from AWS’s, which may lead you to a problematic behavior of your Lambdas.

  • Spring Data Elasticsearch Soft-delete Repositories

    Continuing on the soft-delete repositories topic, let’s look at Elasticsearch.

    It has Spring Data support. And having sorted this out for Mongo, it is quite easily to do the same for Elasticsearch.

  • Spring Data Mongo Soft-delete Repositories

    Everybody loves Spring Data Query Methods. Let’s assume that you need to find all Persons by email. You could do

    @Repository
    public interface PersonRepository extends CrudRepository<Person, String> {
        List<Person> findPersonsByEmail(String email);
    }
    

    Spring Data will automatically create for you an implementation that will look for all Person instances in the corresponding table/collection that have email property equal to the given string.

    Soft-deletion problem

    Now let’s imagine that your repository needs to implement ‘soft-delete’ logic. That means that, when an entity is ‘deleted’, it is actually just labeled as such, so this is actually an update and not a real deletion. In such a storage, you need all the retriever methods to respect that ‘soft-delete’ property: that is, they should not return entities marked as deleted.

    How do we achieve this with a Spring Data repository?

  • Unit-testing a Spring WebFlux streaming controller

    Spring WebFlux makes it easy to write a streaming endpoint for your application. But how do you test it?

  • Handling SSE errors in Spring WebFlux

    Spring WebFlux makes it easy to write a streaming endpoint for your application. One of the options is Server-Sent-Events. Most of the required work is done behind the scenes by Spring Webflux magic, you just need to return a Flux producing the required objects and specify the correct content type. It’s as easy as…

  • Testing an Aspect in a Spring application

    Sometimes, an Aspect is the best tool to solve a task at hand. But how can we unit-test it? An obvious solution is to start up the whole application context, including the Aspect, and then test how it behaves, but this will be actually an integration test; such tests are heavy, and you have less control over the situations you can model in such a test (for example, it may be pretty difficult to simulate an exceptional situation).

  • Cassandra cqlsh client, OperationTimedOut and request timeouts

    I’m used to mysql command line client. If a query runs for a long time, it just keeps running. This is very useful if you feed a script (i.e. a sequence of queries) to mysql client for execution: no matter how long each query executes, the queries are run serially. If nothing breaks in the middle, they all execute successfully.

  • Peculiarities of @ControllerAdvice in Spring MVC

    What is @ControllerAdvice?

    @ControllerAdvice annotation is used to define some attributes for many Spring controllers (@Controller) at a time.

    For example, it can be used for a centralized exception control (with @ExceptionHandler annotation). This post will concentrate on this use.

  • A clean, safe and concise read-only Wicket Model with Java 8 Lambdas

    Wicket framework uses models (IModel implementations) to bind data to components. Let’s say you want to display properties of some object. Here is the data class:

    public class User implements Serializable {
        private final String name;
        private final int age;
        
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
        
        public String getName() {
            return name;
        }
        
        public int getAge() {
            return age;     
        }
    }
    

    You can do the following to display both its properties using Label components:

    public class AbstractReadOnlyModelPanel extends Panel {
        public AbstractReadOnlyModelPanel(String id, IModel<User> model) {
            super(id, model);
            
            add(new Label("name", new AbstractReadOnlyModel<String>() {
                @Override
                public String getObject() {
                    return model.getObject().getName();
                }
            }));
            add(new Label("age", new AbstractReadOnlyModel<Integer>() {
                @Override
                public Integer getObject() {
                    return model.getObject().getAge();
                }
            }));
        }
    }
    

    Straight-forward, type-safe, but not too concise: each label requires 6 lines of code! Of course, we can reduce this count using some optimized coding conventions and so on, but anyway, anonymous classes are very verbose.

  • XSLT to convert log4j.xml config to logback.xml config

    Logback is a modern logging framework widely used nowadays. It has a drop-in replacement for a log4j 1.2 (the previous favorite): logback-classic. But a little problem arises if you have an application which uses log4j and want to migrate it to logback: configuration.

  • Spring Security 3.2+ defaults break Wicket Ajax-based file uploads

    A couple of days ago we have run into a bug: we found that file uploads in our Wicket application have broken. Instead of working as expected, upload button did not work, instead a message appeared in the browser console (this one is for Chrome):

  • ssh reverse tunnel for external internet

    Today I needed to create an ssh reverse tunnel, so when someone connects to a server's port, he is forwarded to my PC's port. A usual thing, nothing special.
    I googled a bit and found a lot of examples.

    ssh -R 8888:localhost:80 user@host.com

    So when a TCP connection is opened to host.com:8888, it actually gets forwarded to my localhost:80.

    Pretty simple. But it did not work.

    After googling and googling and finding all the same simple but not working examples, I finally did the right thing: reading manual.
    It turned out that when server-side bind address is not specified (as it is in my case) it binds to 127.0.0.1 which is not visible from the outside internet. You can specify * or empty string as bind address to make sshd bind to all interfaces, or even specify an IP address to bind to, but any of these will work only if sshd server has GatewayPorts enabled.

    Okay, after adding the following line
    GatewayPorts on
    to the /etc/ssh/sshd_config and restarting sshd it has started to work. Command is:
    ssh -R *:8888:localhost:80 user@host.com
    One more little thing learned.
  • Working around a Selenium Maven plugin problem on Firefox 3

    A couple of days ago I tried Spring Roo. Its ten-minute tutorial offers you to run Selenium tests using the following command:
    mvn selenium:selenese
    I launched it, but console window freezed and nothing happened.
    Looks like it's a problem with Selenium+Firefox 3 (possibly also Ubuntu).
    For me, a solution was simple: just change selenium-maven-plugin version to 1.0.1 (which is the most recent stable version at the time of writing). So plugin definition in Roo-generated application's pom.xml will look like
    <plugin>
       <groupid>org.codehaus.mojo</groupid>
       <artifactid>selenium-maven-plugin</artifactid>
       <version>1.0.1</version>
       <configuration>
         <suite>src/main/webapp/selenium/test-suite.xhtml</suite>
         <browser>*firefox</browser>
         <results>${project.build.directory}/target/selenium.txt</results>
         <starturl>http://localhost:4444/</starturl>
       </configuration>
    </plugin>
    The same applies to using Selenium on Ubuntu+Firefox 3 through JUnit tests: I had to use version 1.0.1 of selenium-maven-plugin to make this work.
  • Testing RTMP streaming with JW Player

    When configuring an RTMP streaming in Flash Player (see previous post for an example), I will use the same examples in this post), it may be hard to tell why it does not work: was URL incorrect? Or you just missed something in your player? In such a case it may be helpful to use JW Player online player constructor.
    1. Go to http://www.longtailvideo.com/support/jw-player-setup-wizard
    2. Select flvplayer with an rtmp stream
    3. In File properties section, set File to your stream name, like 'video1.flv' or 'mp4:video2.mp4' (without quotes)
    4. In External Communitation section, set streamer to the part of URL without your stream name, like rtmp://abcdefghijklmn.cloudfront.net/cfx/st
    5. Press Update Preview & Code button
    6. Press on the player below. If it plays your video correctly, then your bucket+distribution are configured correctly and URL is correct, too
    Note that values for streamer on step 4 and for file on step 3 give you the full streaming URL when concatenated through a slash (/) as described in the aforementioned post.
  • Streaming h264 video from Cloudfront to Flash Player: how-to

    Flash makes it easy to stream a video, at least in theory. With Amazon Cloudfront it's even easier - you just create a bucket, upload a video to it, and it's ready to be streamed via Flash Player.
    Or it seems so.
    There're some details which are documented poorly. I will try to fill this hole.

    Brief algorithm

    To stream a video (including h264) from Cloudfront, you need to do the following:
    1. Create an AWS account
    2. Create an S3 bucket for you videos
    3. Create a Cloudfront distribution for it
    Then, for each file you wish to stream, you will have to do the following:
    1. Upload it to your S3 bucket as a public resource
    2. Stream it through Flash Player using correct URL
    Let's go!

    Configuring software

    To work with S3 and Cloudfront you need some special software. For instance, there's an extension for Firefox called S3Fox. I personally prefer using s3cmd command line program to manage S3, I will provide examples for s3cmd.
    Anyway, when registering in AWS, you will get a couple of pretty long and ugly strings. Those are Access Key and Secret Key. You have to configure your AWS-related software to use these keys for authentication. For s3cmd, the command is
    s3cmd --configure

    Creating an AWS account

    To create an AWS (Amazon Web Services) account.

    Creating an S3 bucket for your videos

    First, you have to create an S3 (Simple Storage Service) bucket for your videos, it will feed them to your Cloudfront distributions.
    s3cmd mb s3://your-bucket-name.you-site.com
    Bucket name must be unique among all buckets, so it may seem reasonable to call your bucket based on your domain name.

    Creating a Cloudfront distribution for your videos

    A distribution must be bound to a bucket. Distribution will distribute any file with public access from a bucket bound to it.
    Distribution may be created using mentioned software or using AWS Console web interface.
    When creating, select 'Streaming' as type as we're going to stream video. Note that you can create several distributions for your bucket, so you may also have access to your bucket via HTTP if you wish. Of course, specify your bucket to which distribution will be bound.
    Distribution takes some time to create. After it completes, you will get a public domain name for it, this will be domain name you will need to construct video URLs.

    Uploading a video to bucket

    When uploading a video to your bucket, make sure that you make it publicly readable.
    s3cmd --acl-public put video.mp4 s3://your-bucket-name.your-site.com/video.mp4
    Note that you don't need to make your whole bucket publicly readable, only files.

    Constructing a URL

    It's not a trivial task to construct a correct URL for streaming, because RTMP (and we are forced to use RTMP for streaming) has its own logic of constructing URLs. And there's still another catch with correct format prefix which you must use if you stream mp4 (or mp3). So I will provide some examples.
    The common schema for Cloudfront is the following:
    rtmp://distribution-domain-name/cfx/st/[type_prefix]stream_name
    • for flv, you don't need a type prefix, and you may supply extension name while it's recommented to omit it.
    • for mp4, you have to use type prefix 'mp4:' (with no quotes) and you must supply extension (mov, mp4, aac, f4v, m4v, m4a - any of these).
    • for mp3, you have to use type prefix 'mp3:'.
    Let's assume you have some video and audio files stored as s3://your-bucket-name.your-site.com/video1.flv, s3://your-bucket-name.your-site.com/video2.mp4 and s3://your-bucket-name.your-site.com/audio.mp3. Assuming that your Cloudfront distribution domain name is abcdefghijklmn.cloudfront.net, you'll have to use the following URLs:
    rtmp://abcdefghijklmn.cloudfront.net/cfx/st/video1
    rtmp://abcdefghijklmn.cloudfront.net/cfx/st/mp4:video2.mp4
    rtmp://abcdefghijklmn.cloudfront.net/cfx/st/mp3:audio.mp3

    Links

    http://livedocs.adobe.com/flex/3/langref/flash/net/NetStream.html#play() - here is more info on type prefixes

subscribe via RSS