Alpine linux – /../jdk8/bin/java: not found

Problem Statement

On Alpine Linux (3.9.4), you installed oracle JDK8 and getting the following error when trying to use it.

  1. /../jdk8/bin/java: not found
  2. /../jdk8/bin/java: No such file or directory

Solution

It is probably glibc is not available. follow the below steps to fix the issue.

$ apk --no-cache add ca-certificates wget
$ wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
$ wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk
$ apk add glibc-2.28-r0.apk

Advertisements

Is recursion always good?

Problem Definition

Is this always correct to say – “Recursive functions are common in computer science because they allow programmers to write efficient programs using a minimal amount of code.”

Below piece of code is simply trying to find the next lexicographical order of string.

Note: Algorithm is not correct. it is this incorrect algorithm highlighted which I will conclude later.

Sample Code

getNextOrder(…) is the recursive function in below sample code.

Source: https://github.com/sabirhussain/java-sample/tree/master/LexicographicalOrder

Run below code with and without Thread.sleep and observe the output. You will get stackoverflow error without Thread.sleep, which is self-explanatory. Hence it is evident that recursive functions are not the best option always.

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;

public class NextLexicographicalOrder {

  public static void main(String[] args) throws IOException {
    try (
      BufferedReader br = new BufferedReader(new FileReader(new File("testcase1.txt")))) {
      String line = null;

      while ((line = br.readLine()) != null) {
        String result = processLine(line);
        try {
          Thread.sleep(50);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }

        System.out.println(line + ": " + result);
      }
    }
  }

  static String processLine(String w) {

    if (w.length() == 1)
      return "no answer";

    char[] chars = w.toCharArray();

    return getNextOrder(chars, chars.length - 1, chars.length - 2);
  }

  static String getNextOrder(char[] chars, int i, int j) {

    if (chars[i] > chars[j]) {
      char tmp = chars[i];
      chars[i] = chars[j];
      chars[j] = tmp;

      if (i == j + 1)
        return new String(chars);

      char[] subChars = Arrays.copyOfRange(chars, j + 1, chars.length);
      Arrays.sort(subChars);

      return new StringBuilder().append(Arrays.copyOfRange(chars, 0, j + 1)).append(subChars).toString();
    }

    if (i == 1)
      return "no answer";

    if (j == 0)
      return getNextOrder(chars, (i - 1), (i - 2));
    else
      return getNextOrder(chars, i, --j);
  }
}

Conclusion

Although recursive functions are an efficient way of implementation wherever possible, in some specific situations it is not the best solution as it may fill up your stack faster than it is garbage collected.

Increase LVM space in VirtualBox

Problem Definition

Getting out of disk space error on your VirtualBox VM where your guest Linux OS is using LVM with Dynamic disk allocation, and you are wondering why this error when available space is 30 GB and used space is only 4 GB.

Solution

  • Login to your vm and run ‘df -h’
    if your output is nearby –>

    then run below 2 steps
  • sudo lvextend -L +2G /dev/mapper/ubuntu--vg-ubuntu--lv
  • sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv
    df -h

DONE!

File Download Component – Java

Problem Definition

Many a time we need to provide file download feature in our application, and it perfectly makes sense to create a component that can be reused.

Solution

This component is created for spring boot web application, although you can customize the code or get the idea for the reusable component.

The Component

FileDownloadHelper this is the main helper class that downloads the file or more technically writes file content on http response.

public class FileDownloadHelper {

    public static ResponseEntity downloadFile(FileResource file, WritableStream stream) {
        Assert.notNull("file and stream parameters are not optional.", file, stream);

        if (!file.exists())
            return ResponseEntity.notFound().build();

        byte[] content = file.getContent();

        if (!FileUtil.verifyChecksum(content, file.getChecksum())) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Verify checksum fail");
        }

        stream.setContentType(file.getContentType());
        stream.write(content);

        return ResponseEntity.ok().build();
    }

}

Supporting Implementaion

FileResource
This allows to wrap underlying complexity of file resource and expose common access pattern.

public interface FileResource {

    String getPath();

    String getChecksum();

    String getContentType();

    boolean exists();

    byte[] getContent();

    InputStream getStream();

}

WritableStream
This allows to wrap writable resource (ex: servlet response) to hide complexity and expose common access pattern.

public interface WritableStream {

    void setContentType(String type);

    void write(byte[] content);
}

In Action

Sample code to download file from google cloud storage.

GoogleFileResource

public final class GoogleFileResource implements FileResource {
    private Blob blob;
    private FileMeta meta;

    public GoogleFileResource(Blob blob, FileMeta meta) {
        this.blob = blob;
        this.meta = meta;
    }

    @Override
    public String getPath() {
        return blob.getName();
    }

    @Override
    public String getChecksum() {
        return meta.getChecksum();
    }

    @Override
    public String getContentType() {
        return meta.getType();
    }

    @Override
    public boolean exists() {
        return blob.exists();
    }

    @Override
    public byte[] getContent() {
        return blob.getContent();
    }

    @Override
    public InputStream getStream() {
        return null;
    }

}

ServletWritableStream

public class ServletWritableStream implements WritableStream {
    private HttpServletResponse response;

    public ServletWritableStream(HttpServletResponse response) {
        Assert.notNull(response);
        this.response = response;
    }

    @Override
    public void setContentType(String type) {
        response.setContentType(type);
    }

    @Override
    public void write(byte[] content) {
        try {
            response.getOutputStream().write(content);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

Final Piece

@GetMapping
public ResponseEntity getFile(@PathVariable String consultationReference,
            HttpServletResponse response) {
        return service.getFile(consultationReference)
                .map(file -> FileDownloadHelper.downloadFile(file, new ServletWritableStream(response)))
                .orElse(ResponseEntity.notFound().build());
    }

Artifactory with Multi-Module Gradle Project

Prerequisites

1. Oracle JDK8

Environment Details

1. OS – Ubuntu 16.04 x64 Server
2. Artifactory – oss-5.3.0

Problem

Publish your jar from Multi-module gradle project and use in other projects.

Steps

Install Artifactory

Start Artifactory

  • Goto artifactory home. (to extracted location)
  • run – bin/artifactory.sh

Setup repository

Your framework project parent/root build.gradle


buildscript {
  repositories {
    jcenter {
      url 'http://localhost:8081/artifactory/jcenter/'
    }
  }

  dependencies {
    //Check for the latest version here: http://plugins.gradle.org/plugin/com.jfrog.artifactory
    classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4+"
  }
}

allprojects {
  apply plugin: 'maven'

  group = 'com.example'
  version = '1.0.0-SNAPSHOT'

  ext {
    springBootVersion = '1.5.2.RELEASE'
  }
}

subprojects {
  apply plugin: 'java'
  apply plugin: 'maven-publish'
  apply plugin: "com.jfrog.artifactory"

  sourceCompatibility = 1.8
  targetCompatibility = 1.8
  tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
  }

  repositories {
    jcenter {
      url 'http://localhost:8081/artifactory/jcenter/'
    }
  }

  dependencies {
    testCompile group: 'junit', name: 'junit', version:'4.12'
  }

  artifactory {
    contextUrl = "${artifactory_contextUrl}" //The base Artifactory URL if not overridden by the publisher/resolver
    publish {
      repository {
        repoKey = 'example-framework-snapshot-local'
        username = "${artifactory_user}"
        password = "${artifactory_password}"
        maven = true
      }
      defaults {
        publications ('mavenJava')
      }
    }

    resolve {
      repository {
        repoKey = 'example-framework-snapshot'
        username = "${artifactory_user}"
        password = "${artifactory_password}"
        maven = true
      }
    }
  }

  publishing {
    publications {
      mavenJava(MavenPublication) {
        from components.java
      }
    }
  }
}

build.gradle for user of your Framework Code

Assuming your virtual repository is ‘example-framework-snapshot’

buildscript {
  ext {
    springBootVersion = '1.5.2.RELEASE'
  }
  repositories {
    maven {
      // Your virtual repository
      url 'http://localhost:8081/artifactory/example-framework-snapshot'
    }
  }
  dependencies {
    classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
  }
}

apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'war'
apply plugin: 'org.springframework.boot'

group = 'com.security.sample'
version = '0.0.1-SNAPSHOT'

description = """sample-security Webapp"""

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
  maven {
    url 'http://localhost:8081/artifactory/example-framework-snapshot'
  }
}

dependencies {
  compile ('com.example:example-security-extras:0.0.1-SNAPSHOT')
  compile ('org.springframework.boot:spring-boot-starter-web')
  compile ('redis.clients:jedis')
  testCompile ('junit:junit')
}

Sorting and Cross Join Problem – Spring Data JPA

Affected Version

Spring boot – 1.2.2
Spring data JPA version – 1.7.2
Spring data common – 1.9.2

Problem Statement

When you use custom query using @Query in your spring data JPA repository and pass sort parameter, where sort parameter is a child attribute; the query generated uses cross join instead of left outer join. This gives unexpected result.

Problem Sample


@Query("SELECT e FROM EventApprovalRequest e WHERE e.approvalRequestType = (:approvalRequestType) "
+ "AND e.status = (:status)")
Page getEventsForApproval(
@Param("approvalRequestType") int approvalRequestType, @Param("status") int status, Pageable pageable);

Solution

Pre-define left outer join in your query.

@Query("SELECT e FROM EventApprovalRequest e LEFT OUTER JOIN e.event LEFT OUTER JOIN e.event.director WHERE e.approvalRequestType = (:approvalRequestType) "
+ "AND e.status = (:status)")
Page getEventsForApproval(
@Param("approvalRequestType") int approvalRequestType, @Param("status") int status, Pageable pageable);

Get Enum type with id

Here is a simple technique to retrieve Enum type using custom ‘id’ property instead of name.

Define Contract

/**
 * Contract that will allow Types with id to have generic implementation.
 */
public interface IdentifierType<T> {
  T getId();
}

Apply Contract

public enum EntityType implements IdentifierType<Integer> {
  ENTITY1(1, "ONE), ENTITY2(2, "TWO");

  private Integer id;
  private String name;

  private EntityType(int id, String name) {
    this.id = id;
    this.name = name;
  }

  public static EntityType valueOf(Integer id) {
    return EnumHelper.INSTANCE.valueOf(id, EntityType.values());
  }

  @Override
  public Integer getId() {
    return id;
  }
}

Make use of contract (helper)

public enum EnumHelper {
  INSTANCE;

  /**
   * This will return {@link Enum} constant out of provided {@link Enum} values with the specified id.
   * @param id the id of the constant to return.
   * @param values the {@link Enum} constants of specified type.
   * @return the {@link Enum} constant.
   */
  public <T extends IdentifierType<S>, S> T valueOf(S id, T[] values) {
    if (!values[0].getClass().isEnum()) {
        throw new IllegalArgumentException("Values provided to scan is not an Enum");
    }

    T type = null;

    for (int i = 0; i < values.length && type == null; i++) {
        if (values[i].getId().equals(id)) {
            type = values[i];
        }
    }

    return type;
  }
}