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());
    }
Advertisements

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;
  }
}

Simple Lambda – Java8

public class LambdaSample {
  protected interface SimpleCalc {
    int operation(int a, int b);
  }
  public static void main(String[] args) {
    /*
     * Old style
     */
    SimpleCalc add = new SimpleCalc() {
    @Override
    public int operation(int a, int b) {
      return a + b;
    }
  };
  System.out.println(add.operation(2, 5));
  /*
   * New style - Lambda Expression
   */
  SimpleCalc multiply = (a, b) -> a * b;
  System.out.println(multiply.operation(2, 5));
  }
}

In the above code you can see the old vs new style of anonymous function creation. Lambda expression makes it short, concise and readable. [its look readable to me :)]