Friday, 22 May 2020

Containerizing Angular application using Docker

Let's containerize angular application using Docker.

Pre-requisites for exercise:


  1. Install Docker for Desktop
  2. Install Node js
  3. Install Angular CLI (make sure you have the latest version of Angular CLI installed).

You must have an Angular application to containerize it. If you already have the application, then you can skip Angular Application creation step.

Create Angular Application


1. Create an folder/directory on your machine, let's say HelloWorldApp.
2. Open command-line and navigate to this directory.
3. Create Angular application using ng new HelloWorldAngular command.

Angular Application Creation



4. Navigate to created project folder cd HelloWorldAngular
5. To make sure app is running. run ng serve command here, then navigate to https://locahost:4200 in your browser.
6. Feel free to make any changes (add new components/modify existing components.

Creating Docker file


To create a docker image we must create the docker file and specify the required steps to build the image.
1. Create the Dockerfile (name of the file must be Dockerfile) without any extension in the root of your project.
2. Let's update our empty Dockerfile.

Note : Here we are going to use multistage build to create an optimized image.


Below is the detail of Dockerfile instructions.

FROM node:latest As builder

This line will tell the docker to pull the node image with tag latest if the images don't exist. We are also giving a friendly name (alias) builder to this image so we can refer it later.

WORKDIR /usr/src/app

This WORKDIR command will create the working directory in our docker image. going forward any command will be run in the context of this directory.

COPY package.json package-lock.json ./

This COPY command will copy package.json and package-lock.json from our current directory to the root of our working directory inside a container which is /usr/src/app.

RUN npm install

This RUN command will restore node_modules define in our package.json

COPY . .
This COPY command copies all the files from our current directory to the container working directory. this will copy all our source files.

RUN npm run build --prod

This command will build our angular project in production mode and create production ready files in dist/HelloWorldAngular folder.

FROM nginx:latest

This line will create a second stage nginx container where we will copy the compiled output from our build stage.

COPY --from=builder /usr/src/app/dist/HelloWorldAngular/ /usr/share/nginx/html

This is the final command of our docker file. This will copy the compiled angular app from builder stage path /usr/src/app/dist/HelloWorldAngular/ to nginx container. 

Complete Dockerfile


Complete Dockerfile

Building a docker image


Navigate to the project folder in command prompt and run the below command to build the image.


docker build . -t  jagdevsingh2020/helloworldappimage

This command will look for a docker file in the current directory and create the image. The  default convention is <DockerHubUsername>/<ImageName> e.g. jagdevsingh2020/helloworldappimage. jagdevsingh2020 is my docker hub username and helloworldappimage is the image name.
Run docker images command to verify above image. This will list all the Docker images on your machine.

Running a container


You can run the docker image using the below command.

docker run -p 4000:80 
 jagdevsingh2020/helloworldappimage

Here -p flag publishes all exposed ports to the host interfaces. we are publishing container port 80 to host 4000 port.

Navigate to your browser with http://localhost:4000 to verify your application.

Happy Learning !!

Tuesday, 28 April 2020

UnsupportedOperationException at java.util.AbstractList.add

While working on JAVA assignment, discovered strange error while trying to add an element to list. I am using example code to demonstrate and fix this exception.

Note : Here existing array is converted into list using JAVA API.

Code Sample :
    public static void main(String[] args) {     
        Integer [] array = {1,2,3};
        List<Integer> asList = Arrays.asList(array);
        asList.add(0, 100);
        asList.forEach(s-> System.out.println(s+ " "));
    }

Error : Exception in thread "main" java.lang.UnsupportedOperationException
     at java.base/java.util.AbstractList.add(AbstractList.java:153)
     at com.learning.concepts.PlusOne.main(PlusOne.java:13)

Root Cause : Arrays.asList() method returns a non-resizable list backed by the array. From that method's documentation:
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.)
Solution : In order to use a resizable list use the following to convert array into list.

List<Integer> asList = new ArrayList<Integer>(Arrays.asList(array));

Thursday, 2 April 2020

A quick and practical example of Hexagonal Architecture in Java

1. Overview


In this tutorial, we'll discuss Hexagonal Architecture in Java through a working example.

2. Hexagonal Architecture


The core concept of this pattern is to implement the business logic inside the hexagon and expose it outside through the ports and adapters. The component that remains inside usually consists of application and domain layers, along with the core business logic. Whereas, the component for the outside world consists of layers like UI and Database or third party integrations.
In terms of programming (implementation), a port is an interface while an adapter is the concrete implementation of a given port.

3. Hexagonal Architecture example in Java


Let's create a simple Spring Boot REST App and try to register/view Student details using the Hexagonal Architecture.

3.1 Define Domain layer


To start with, we'll create an entity named Student. Then, we'll  add StudentService class to keep the core business logic to persist\view data. Here, the Student and StudentService are part of the inside component. Therefore, we'll create ports to expose them.
public class Student { 
    private int studentId; 
    private String name; 
    private int age; 
}

public interface StudentService {
    public List<Student> findAll();
    public void save(Student student);
}
Let's implement StudentService interface now.
@Service
public class StudentServiceImpl implements StudentService {
    private StudentDBPort studentDBPort;

    @Autowired
    public StudentServiceImpl(StudentDBPort studentDBPort) {
        super();
        this.studentDBPort = studentDBPort;
    }

    @Override public List<Student> findAll() {
        return studentDBPort.findAll();
    }

    @Override public void save(Student student) {
        studentDBPort.save(student);
    }
}

3.2 Declare Ports


Then, we'll create the StudentDBPort interface to communicate with the database:
public interface StudentDBPort {
    public List<Student> findAll();
    public void save(Student student);
}

3.3 Implement Adapters


Let's create the StudentControllerAdapter class that  act as a RestController. Therefore, it'll act as an adapter to REST client.
public class StudentControllerAdapter implements StudentRESTPort {
    @Autowired
    private StudentService studentService;
 
    @RequestMapping(method = RequestMethod.POST, value = "/register")
    public Student registerStudent(@RequestBody Student student) {
        studentService.save(student);
        return student;
    }
 
    @RequestMapping(method = RequestMethod.GET, value = "/viewAll")
    public List<Student> getAllStudents() {
        return studentService.findAll();
    }
}
Then, we'll create the StudentServiceDBAdapter class that implements the StudentDBPort interface. So, it'll behave as an adapter to persist data in the database:
public class StudentServiceDBAdapter implements StudentDBPort {
    private EntityManager entityManager;

    @Override
    public List<Student> findAll() {
        Session currentSession = entityManager.unwrap(Session.class);
        Query<Student> theQuery = currentSession.createQuery("from Student", Student.class);
        List<Student> students = theQuery.getResultList();
        return students;
    }

    @Override
    public void save(Student student) {
        Session currentSession = entityManager.unwrap(Session.class);
        currentSession.saveOrUpdate(student);
    }
}
That's it, we've successfully separated our App into the inside and outside components.

4. Benefits


The benefits of this architecture are:
  • Independence : The core layer is independent of outer layers
  • Testability : Each dependent (outer) component could be easily replaced with a stub implementation so that any component can be tested with ease
  • Flexibility : Any number of ports can be added easily to serve multiple functionalities\channels


5. Conclusion


In this article, we've learned how to use Hexagonal Architecture in Java. We've seen the core business logic can be exposed as ports via interfaces and consumed by different adapters through implementation classes.

Monday, 19 August 2019

Eclipse Maven Error | No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?

Faced below error while trying to maven build in Eclipse.

No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?


Solution :


  1. Eclipse -> window -> preference.
  2. Select installed JREs -> Edit
  3. Add External Jars
  4. select tools.jar from java/JDKx.x/lib folder.
  5. Click Finish

Friday, 16 August 2019

Spring Boot | Disable the Spring Banner in logs

When we start spring application below banner appears in logs.


You can remove this by using below properties in application.properties.


spring.main.banner-mode=off

Clean logs after applying this change.



Thursday, 15 August 2019

Spring Boot RESTful Web Service Complete Example

While exploring spring boot, I have decided to implement simple REST service to demonstrate GET, POST, PUT, and DELETE calls.

Prerequisite for this project :

- Eclipse with STS (Spring tool Suite) plugin
- SOAPUI
- JAVA 8
- Maven

1. Create Eclipse project.
Select File->New-> Project->Spring Starter Project
Follow the wizards and finally click on finish




2. Define Employee bean.

Monday, 29 July 2019

Common git issues and their solution

While using git, I faced some small issues and found their solution online. Here is the consolidated list.

1. Refusing to merge unrelated histories.
Command : git pull
Error : fatal: refusing to merge unrelated histories
Solution : git pull --allow-unrelated-histories

2. There is no tracking information for the current branch.
Command : git pull
Error : There is no tracking information for the current branch. Please specify which branch you want to merge with.
Solution : git branch --set-upstream-to=origin/master master

3. Not a git repository.
Command : git remote add origin https://github.com/jagdevsingh87/ATG-REST-case-study.git
Error : fatal: not a git repository (or any of the parent directories): .git
Solution : git init