The case for frameworks over libraries (Spring Boot vs Dropwizard)

I am working with a customer where customer took the decision to go with Dropwizard instead of Spring Boot(or Spring ecosystem). I initially respected their decision and decided to give Dropwizard a fair chance. Now after spending a couple of months building a system that uses Dropwizard I don’t recommend it. I wrote about my initial thoughts here.

There are three main advantages of a battle tested and highly used framework like Spring:

  • Good APIs
  • Solution to common problems
  • Good searchable documentation

Let me help you understand that by taking an example of integrating Kakfa in a Dropwizard application. The Dropwizard official organization provides a Kafka bundle[1] so we decided to use it for adding Kafka support. I found following issues with it:

Poor API: When you create the KafkaConsumerBundle in the *Application class you are forced to provide an implementation of ConsumerRebalanceListener. KafkaConsumerBundle does not do anything with it but it forces you to provide it [2]. If you read Kafka documentation you need to provide ConsumerRebalanceListener not at the time of creation but when you subscribe it. ConsumerRebalanceListener is used to commit the offsets in case of partitions. There is also an open issue [3] in Github repo on the same without any answer from the maintainers.

Incomplete configuration: The Dropwizard Kafka bundle does not support all the Kafka producer and consumer configuration properties. For example, it is often recommended to set number of retries in producer to Integer.MAX_VALUE and rely on delivery.timeout.ms to limit the number of retries. Since it is not a configuration option in Dropwizard bundle you have to hardcode it during the bundle creation.

Missing solution to common problems: Any real world Kafka application need to solve for these three common problems. Spring Kafka part of Spring ecosystem provides solution to these problems.

  1. It does not provide serializer/deserialzer for JSON or any other format. You have to write one yourself or find a library that implements it.
  2. Handling of Poison pill messages using ErrorHandlingDeserializer
  3. Publishing of Poison pill messages to a dead letter topic

Conclusion

Yes, you can write your own bundle which fixes all these issues. But, then you are doing the undifferentiated work. Your team can spend time on writing business logic rather than writing and maintain this code. There is no right or wrong answer here. There is a cost that has to be paid when you take these decisions. You should keep that in mind. There is no free lunch.

Resources

  1. https://github.com/dropwizard/dropwizard-kafka
  2. https://github.com/dropwizard/dropwizard-kafka/blob/master/src/main/java/io/dropwizard/kafka/KafkaConsumerBundle.java#L33
  3. https://github.com/dropwizard/dropwizard-kafka/issues/179

Adding copy to clipboard functionality in Angular application

Today, I had to work on an application that required copy to clipboard functionality. Below is a step by step tutorial that will help you add copy to clipboard functionality. The reason I had to implement copy to clipboard functionality is that with dnd-list copy feature gets broken so I needed a way to give user a copy functionality.

Angular version being used in Angular 5.

Step 1: Create Angular application

$ ng new myapp

Step 2: Install ngx-clipboard and ng2-toastr

$ npm install --save ng2-toastr ngx-clipboard

Step 3: Configure modules

In the app.module.ts, add ClipboardModule and ToastModule

import { ToastModule } from 'ng2-toastr/ng2-toastr';
import { ClipboardModule } from 'ngx-clipboard';
@NgModule({
    imports: [
        BrowserAnimationsModule,
        ToastModule.forRoot(),
        ClipboardModule
    ],
    declarations: [
        AppComponent
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

Step 4: Add ngx-clipboard directive

Update app.component.html

<div class="col-11 p-2 lh-condensed">
      <h6 class="font-weight-bold">
        {{task.title}}
        <div class="float-right">
          <i class="ft-chevron-down"></i>
          <div class="dropdown-menu">
            Copy
            Edit
            Delete
          </div>
        </div>
      </h6>
</div>

Update app.component.html

  copyToClipboard() {
    this.toastr.success('Copied to clipboard', 'Success!');
  }

Updating Angular Projects Generated By Angular CLI To Latest Version

Today, I wanted to update one of my starter projects to use the latest version of Angular. I built starter project with Angular 5.0.0 and I wanted to update it to latest Angular version which is 5.0.4. Below are the steps, you need to follow to update your project. Navigate to your project working directory and do the following:

Step 1: Remove node_modules

$ rm -rf node_modules/

Step 2: Update angular-cli dependency to latest version

You can check latest version at https://github.com/angular/angular-cli/releases.

Once you know the version, update the @angular/cli version in the package.json to the latest version.

Step 3: Install and run the upgrade

$ yarn install
$ yarn upgrade

yarn upgrade will update all the dependencies to the latest version.

Step 4: Run the application

Now, you can run the application using the yarn start -o command.

Sentiment Analysis in Scala with Stanford CoreNLP

In this post, we will learn how to use Stanford CoreNLP library for performing sentiment analysis of unstructured text in Scala.

Sentiment analysis or opinion mining is a field that uses natural language processing to analyze sentiments in a given text. It has applications in many domains ranging from marketing to customer service. Few years back, I wrote a simple Java application using Naive Bayes classifier to determine whether people liked a movie or not based on sentiment analysis of tweets about a movie. Continue reading “Sentiment Analysis in Scala with Stanford CoreNLP”

Docker Machine Error Unable to Query Docker Version

Today, when I created a new docker machine I started getting Unable to query docker version: Get https://192.168.99.101:2376/v1.15/version: x509: certificate is valid for 192.168.99.100, not 192.168.99.101

To fix this error, run the following command.

docker-machine regenerate-certs default

Please change default with name of your docker machine.

How to programmatically get process id of a Java process

This is how you can get process id of a Java process.

import java.lang.management.ManagementFactory;

public class JavaProcessId {

    public static void main(String[] args) {
        String vmName = ManagementFactory.getRuntimeMXBean().getName();
        int p = vmName.indexOf("@");
        String pid = vmName.substring(0, p);
        System.out.println(pid);
    }
}

Docker REST API wget request and responses

This blog will list Docker wget requests. This assumes you are using boot2docker with https connection.

Create an Image

POST /images/create

$ wget --method=POST --header="Content-Type:application/json" --no-check-certificate 
--certificate=$DOCKER_CERT_PATH/cert.pem --private-key=$DOCKER_CERT_PATH/key.pem 
https://192.168.99.100:2376/images/create\?fromImage\=busybox -O - -v

Response

--2015-10-03 14:15:07--  https://192.168.99.100:2376/images/create?fromImage=busybox
Connecting to 192.168.99.100:2376... connected.
WARNING: cannot verify 192.168.99.100's certificate, issued by '/O=shekhargulati':
  Unable to locally verify the issuer's authority.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/json]
Saving to: 'STDOUT'

-                                                [<=>                                                                                            ]       0  --.-KB/s             {"status":"Pulling from library/busybox","id":"1-ubuntu"}
{"status":"Already exists","progressDetail":{},"id":"6003abefd7b2"}{"status":"Already exists","progressDetail":{},"id":"8171cf9d0131"}{"status":"Digest: sha256:e51c3b513c0b04603c32d6961858c5d380c94c1eb03ad8f66685ef3ddf280114"}
{"status":"Pulling from library/busybox","id":"1.21-ubuntu"}
-                                                [ <=>                                                                                           

List images with dangling true filter

GET /images/json

Docker REST API documentation does not give an example of how to pass filters . You have to JSON encode them. This means you have to first convert them to JSON like {"dangling":["true"]} and then use utility classes like Java’s URLEncoder.encode(json, UTF_8.name()) to encode json.

$ wget -i --header="Content-Type:application/json" --no-check-certificate 
--certificate=$DOCKER_CERT_PATH/cert.pem --private-key=$DOCKER_CERT_PATH/key.pem 
https://192.168.99.100:2376/images/json??all=false&filters=%7B%22dangling%22%3A%5B%22true%22%5D%7D -O - -v

Tag an image into a repository

POST /images/(name)/tag

$ wget --method=POST --header="Content-Type:application/json" --no-check-certificate 
--certificate=$DOCKER_CERT_PATH/cert.pem --private-key=$DOCKER_CERT_PATH/key.pem https://192.168.99.100:2376/images/openshift/hello-openshift/tag?repo=shekhargulati/hello-openshift&tag=v42 -O - -v

Get Container Logs

GET /containers/(id)/logs

$ wget --method=GET --header="Accept: application/vnd.docker.raw-stream" 
--no-check-certificate --certificate=$DOCKER_CERT_PATH/cert.pem 
--private-key=$DOCKER_CERT_PATH/key.pem 
https://192.168.99.100:2376/containers/05c49c850f83/logs?stderr=1&stdout=1&timestamps=1&follow=1&tail=10 -O - -v

Exec Start

POST /exec/(id)/start

wget --method=POST --header="Accept:application/vnd.docker.raw-stream" --header="Content-Type:application/json" --body-data '{"Detach": false,"Tty": false}' --no-check-certificate --certificate=$DOCKER_CERT_PATH/cert.pem --private-key=$DOCKER_CERT_PATH/key.pem https://192.168.99.100:2376/exec/c481eeb18bf58cd5b1375fea57b7449f50f823ce3724a1eb344fb3fe5c1b6cf9/start -O - -v

XWiki on OpenShift

1. Create an OpenShift application using following command
$ rhc app-create xwiki jbosseap –gear large

2. Downloaded the xwiki war file from the official web site.

3. Extracted the war file using $ jar xfv xwiki.war

4. Downloaded three jars — guice-servlet, guice, and h2 from http://mvnrepository.com/ and placed the jars in WEB-INF/lib directory. The application expects these jars but don’t bundle them.

5. Update the hibernate.cfg.xml. Basically, we have commented out hsql and uncommented h2. The NullPointerException that you were seeing was because xwiki does not work with JNDI datasource so you have to bind the url manually. If you want to use postgres or mysql then use proper connection url, username, password etc.

6. Pack the war file again using $jar cfv ROOT.war .

7. Copy the artifact to deployments folder in your app source code. Please delete src/ and pom.xml as you are deploying war file.

8. Git commit and push the war.

9. Check the logs.