Auto Deployment of Dockerized Spring-boot Application using Bitbucket

Idea behind this blog to walk through the auto build of docker image in docker hub for Spring boot application.

Note:- This method is not production level , so use it for staging or development phase only.
(Why it is not suitable for production ?)
[As we have to push the jar to the git repository, to reduce few steps.]

Technology Stack Used

    * Spring Boot [1.4.1 Release]
    * Java 8
    * Maven 2
    * Bit Bucket
    * Docker Hub

Prerequisite

    * Docker Hub Account
    * Bit Bucket Account
    * Minimum knowledge of Spring boot and Java
    * Link Bit Bucket to Docker Hub. CLICK HERE for the reference.

Steps

    1.Create Spring boot Application Capable of creating docker image

      * Create simple spring boot application with web module.[CLICK HERE to create using spring start.io or get it from BIT-BUCKET repo (master branch)].
      * Add Simple test controller to the Spring Project or check out to the branch controller-test.
      * Add Docker support to your current spring boot application or check out to branch docker-support. [To learn how to add docker support to spring boot application you check this blog.]

    2. Create New Repository and link for auto creation of image

      1. Go to docker hub and click on create -> create automatic build
      2. Click on create Auto-build bit-bucket
      3. Select the desired bit bucket repository
      4. Fill required information and click on create.
      5. Go to build setting and provide the branch name from which image should be created and save changes.
      6. Click on build details , it will be empty right now
      7. Make Some changes in that particular branch and push it to the Origin.
      8. Now again check the build details tab , there will be new entry populated with status queued.
      9. Wait for some time its status will be change to building then success.
      10. Now your docker image is ready to use.

    3. Test created docker image

      1. Now pull the docker image
      2. Run the docker image with command [docker run –name docker.test -d -p 8088:8080 jainamit333/docker.demo:docker-support]
      3. Navigate to http://localhost:8088/docker/test.It will show the desired result.
Advertisements

Hazelcast Integration With SpringBoot

Target Audience

Developers who are familiar with Java and Spring Boot [with maven]

We all are building various applications in Spring Boot. Spring boot is a simple lightweight spring application with the integrated server. We can run java[spring] application without any hassle, with most of the things are driven by application properties.  We run single Spring Boot application in the single JVM. Many times we have to run more than one instance of the same application, to manage a large number of requests. We put these instances behind the load balancer, and load balancer will decide which instance should handle the current request.

Simple Pictorial Design

Screen Shot 2018-04-09 at 4.20.39 PM

So our request comes to the load balancer. The load balancer is the entry point of the request. Here we have App 1, which have 3 instances.

Instance: Same Application running in the different server [or in there scope].

So, whenever request goes to any of the instances of App 1, it should behave in the same manner. We create multiple instances so that we can handle more requests. Consider these 3 green regions as separate JVM [seperate tomcat sever].

As we all know two JVMs does not tall to each other, We can consider JVM as an isolated boundary to run a Java application.

Problem Statement

Now suppose you want to somehow share data between these 3 different instances running on different JVM. Assume you need to count of the total number of request server by App 1. If we create a single variable in App1, which will be auto incremented each time request comes to application, it will not solve our problem. Lets name variable requestCounter. Now suppose the total number of request come to load balancer be 3.

Flow Of Request

  • Request 1 goes to instance 1
  • Request 2 goes to instance 2
  • Request 3 goes to instance 1

If We request for the total number of requests server by App 1

  • Instance 1 will return 2
  • Instance 2 will return 1
  • Instance 3 will return 0

Though App 1 serves total number 3 request, all instance provide the wrong result. This is because  we are saving the requestCounter variable at an individual instance, thus every instance is giving the response of its state. We can either get the count from all the instance and sum it, but assume if you have hundred of instance of the same application, how you will do that.Even if we are ready to call each instance, we need to maintain the IP address of all the instances which can be very difficult.

For the same, we will you Hazelcast. What Hazelcast  will do, it will share the state of variable among different instances [JVM].  So in this blog, we will create a simple Spring Boot Application with HazelCast support. And try to share a single long variable among the different instances of Application.

Spring-boot  Setup With Hazelcast

Create Spring Boot Application[Sample Application on Git]

Go to Start Spring IO to create a vanilla Spring-boot Application with Java, Maven and Spring Web as the dependency.

Add HazelCast dependency in the pom.xml


 com.hazelcast
 hazelcast-spring 

Create a class HazelcastConfig inside config package [create package also]

@Configuration
public class HazelcastConfig {

@Bean
public Config hazelConfig(){

Config config = new Config();
config.setInstanceName("hazel-test");
config.getGroupConfig().setName("dev").setPassword("pass");
return config;
}
}

 

  • Line 8 represents the instance name, it should  be different for each instance, in our case Instance 1, Instance 2 and Instance 3
  • Line 9 represents the group. in our case it will be App 1, Since there can be much application you are running, you want to share hazelcast cluster among instances of the same app. In the code above we have used dev [App1]. On the same line, we have set the password also, as to avoid adding the cluster of different instance among the same group.

Now add the TestController, which will use the shared variable.

@RestController
@RequestMapping(value = "/api")
public class TestController {

@Autowired
private HazelcastInstance instance;

@RequestMapping(value = "test")
public String appName(){

return "App1" + instance.getAtomicLong("long-test").incrementAndGet();
}


}
  • Line 6, we have bound the hazelcast instance.
  • Line 11, we are taking Atomic long [“long-test”] variable and simultaneously increasing its value.

Now your code is ready, start this spring boot application twice on the different port. Let’s assume we have started two instances on port 8080, 8081.

 

This is a very simple POC for haze-cast integration with spring boot, it has enormous usecase, We will see some the use cases.

Other Use Cases

  • To maintain the session amoung distributed application.
  • Have distributed cache, [If we maintain cache at the instance level, then cache created at instance 1 will not benefit the instance 2]
  • Distributed in-memory data storage.[Hazelcast contain replica also in case some instance goes down]

 

 

 

 

SpringBoot With Angular 4 Integration and Social Authentication

As a full stack developer, we need to create an application with both frontend-end and backend.

Today we will create a simple full stack application which will have a social login using Google authentication.The area on which we want to focus is how to integrate google social authentication to spring-boot, with logout functionality. And when angular 4 is used in spring-boot application to build the UI, how we will manage the routes, as we know that both angular and have routes, so how our application will resolve which route it has to call.

Tech Stack

  • Angular 4
  • SpringBoot
  • Gradle

Prerequisites

Let’s start creating an application

  • Create a simple spring boot application using Spring.io
    • Project Type with gradle and Java
    • Add necessary description, group, and artifact
    • Add following dependencies to it.

compile 'org.springframework.cloud:spring-cloud-starter-config'
compile('org.springframework.boot:spring-boot-starter-web')
compile("org.springframework.boot:spring-boot-starter-tomcat")
compile 'org.springframework.security:spring-security-web'
compile 'org.springframework.security:spring-security-config'
compile 'org.springframework.security.oauth:spring-security-oauth2'
compile 'org.apache.httpcomponents:httpclient'
compile("io.springfox:springfox-swagger2:2.6.1")
compile("io.springfox:springfox-swagger-ui:2.6.1")

testCompile('org.springframework.boot:spring-boot-starter-test')
compile group: 'org.slf4j' , name: 'slf4j-api' , version: '1.7.22'
compile group: 'io.jsonwebtoken' , name: 'jjwt' , version: '0.7.0'
compile group: 'commons-io' , name: 'commons-io', version: '2.5'
compile group: 'org.projectlombok' , name: 'lombok' , version: '1.16.12'

These dependencies will allow us to enable the google authentication on the top of normal spring boot application.

  • Create the property file application-local.yml in the java main resources.

security:
oauth2:
client:
clientId: ******.apps.googleusercontent.com
clientSecret: ********
accessTokenUri: https://www.googleapis.com/oauth2/v4/token
userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth
clientAuthenticationScheme: form
scope:
- openid
- email
- profile
resource:
userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo
preferTokenInfo: true

user:
role: test-role

We have created a property file to enable google authentication against the particular client.Replace the * with your actual data.

  • Create bootstrap.yml with following data.
<pre>spring:
  application:
    name: frontend
  profiles:
    active: local
  cloud:
    config:
      uri: http://localhost:8888
      enabled: true</pre>

It will help us to give the name to our application and will activate “LOCAL” profile.

  • Create a Security Config java file “SpringConfig” on the same level as of the main file.

package com.test.practise;

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers( "/login","/public/**", "/resources/**","/resources/public/**")
                    .permitAll()
                .antMatchers("/","/api/**").authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/");
    }
}

It will apply authentication to all the path accept /login,  /public,  /resources/public/.

  • Add controller for logout “SecurityController”
<pre>package com.test.practise.controller;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
public class SecurityController {


    @RequestMapping(value="/logout", method = RequestMethod.GET)
    public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null){
            new SecurityContextLogoutHandler().logout(request, response, auth);
        }
        return "redirect:/";
    }
}
</pre>

It will enable the logout URL, which will delete the session.

  • We are not pretty much done with the spring side coding, but we have not added any view or frontend related code yet. We will create the angular project now.
  • Go to the root of the project and create the angular project angular-cli.

ng new webui

It will create a new project directory for frontend inside our current project directory.

  • Navigate to a webui directory which you have created, and make 3 testing controller using the following command.

ng g component landingComponent

ng g component homeComponent

ng g component settingComponent

These are the dummy component to show the routing.

  • Now we will mention our routes in the angular project in file app.module.ts

<pre>import {RouterModule, Routes} from "@angular/router";</pre>


const appRoutes: Routes =[

{path:'',component:LandingComponent},
{path:'welcome',component:WelcomeComponent},
{path:'setting',component:SettingComponent}

]

 

 

  • Add routing module in Imports in the same file.
<pre>@NgModule({
  declarations: [
    AppComponent,
    WelcomeComponent,
    SettingComponent,
    LandingComponent
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot(appRoutes,{enableTracing:true})
  ],
  providers: [],
  bootstrap: [AppComponent]
})

</pre>
  • replace the code of app.component.html the main page of ui with following code.

<pre>&lt;!–The content below is only a placeholder and can be replaced.–&gt;
&lt;div style="text-align:center"&gt;
&lt;h1&gt;
Welcome to {{title}}!!
&lt;/h1&gt;
&lt;img width="300" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojREQwMDMxO30NCgkuc3Qxe2ZpbGw6I0MzMDAyRjt9DQoJLnN0MntmaWxsOiNGRkZGRkY7fQ0KPC9zdHlsZT4NCjxnPg0KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMTI1LDMwIDEyNSwzMCAxMjUsMzAgMzEuOSw2My4yIDQ2LjEsMTg2LjMgMTI1LDIzMCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAJIi8+DQoJPHBvbHlnb24gY2xhc3M9InN0MSIgcG9pbnRzPSIxMjUsMzAgMTI1LDUyLjIgMTI1LDUyLjEgMTI1LDE1My40IDEyNSwxNTMuNCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAxMjUsMzAgCSIvPg0KCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMjUsNTIuMUw2Ni44LDE4Mi42aDBoMjEuN2gwbDExLjctMjkuMmg0OS40bDExLjcsMjkuMmgwaDIxLjdoMEwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMQ0KCQlMMTI1LDUyLjF6IE0xNDIsMTM1LjRIMTA4bDE3LTQwLjlMMTQyLDEzNS40eiIvPg0KPC9nPg0KPC9zdmc+DQo="&gt;
&lt;/div&gt;
&lt;a href="/setting"&gt;Direct Setting&lt;/a&gt;
&lt;a href="/welcome"&gt;Direct Welcome&lt;/a&gt;
&lt;nav&gt;
&lt;a routerLink="/" routerLinkActive="active"&gt;Landing Page&lt;/a&gt;
&lt;a routerLink="/welcome" routerLinkActive="active"&gt;Welcome Page&lt;/a&gt;
&lt;a routerLink="/setting" routerLinkActive="active"&gt;Setting Page&lt;/a&gt;
&lt;/nav&gt;
&lt;router-outlet&gt;&lt;/router-outlet&gt;

</pre>

It will create the routes .First two route for setting and welcome is using href. normal HTML routes and then we have refined routes using routerLink.

  • Build the frontend application

ng build

  • Now we will make changes in spring application to consume this frontend code.First of all, we will add the  code in our build.gradle to copy the frontend code and place it in resource so that it can be consume by spring-boot.
  • Add following task to build.gradle

<pre>

task removeWebui(type: Delete) {
delete "${sourceSets.main.resources.srcDirs[0]}/webui"
}

task copyWebui(type: Copy) {
from "webui/dist"

into "${sourceSets.main.resources.srcDirs[0]}/webui"
exclude "*.gz"
//eachFile { println it.name }
}

task downloadRedoc(type: Download) {
src "https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js&quot;
dest "${sourceSets.main.resources.srcDirs[0]}/public/redoc"
overwrite true
}

task var &lt;&lt; {
sourceSets {
main {
println "java.srcDirs = ${java.srcDirs}"
println "resources.srcDirs = ${resources.srcDirs[0]}"
println "output.classesDir = ${output.classesDir}"
println "output.resourcesDir = ${output.resourcesDir}"
}
}
}

compileJava.dependsOn downloadRedoc
copyWebui.dependsOn removeWebui
compileJava.dependsOn copyWebui</pre>

  • Create controller for APIs “WebRestController

package com.test.practise.controller;

import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RefreshScope
@RestController
@RequestMapping("/api")
public class WebRestController {

@RequestMapping("test")
public String test(){
return "test api data";
}


}
  • Create a view controller for enabling angular routes
<pre>package com.test.practise.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import springfox.documentation.annotations.ApiIgnore;


@Slf4j
@ApiIgnore
@Controller
public class ViewController {

    @RequestMapping({ "/","/welcome" })
    public String views() {
        return "forward:/index.html";
    }

}</pre>

This view controller will enable the spring to resolve these URL as angular URL.

 

Now we are good to go.Run the spring boot application using gradle bootRun.it will start the application.Once you will try to react the application from the browser, it will navigate you to google login first.

On Successful login, you will see the angular page.So till now we are pretty much done with authentication part. Now comes the routing part.

Now try to navigate to welcome page and setting page using above router.In this case, the welcome route will be successful but setting URL will fail, as we have not mentioned it in ViewController.

But when we try the routes which are below one, every route will work fine, as it is using angular routes.

For reference, you can check the GIT REPO with sample working code.

 

Find the day on which stock should be bought and sell, to have maximum profit, Stock can be bought and sold only once.

Problem Explanation

Given an array with the price of stocks on different days. A person can buy and sell stock only once.Compute the maximum profit can be made in that single transaction.

If person cannot make any profit, return 0 as an answer

Example

Sample Input:  [9,8,7,6,5,4,3]  Expected output: 6 {9-3}

Sample Input:  [3,4,5,6,7,8,9]  Expected output: 0

Sample Input: [7,1,5,3,6,4]  Expected output: 6 {7-1}

Solution

For this solution we will use Print next Greatest Element for entry in an Array


public int currentSolution(int[] input){

<code class="java keyword">if</code><code class="java plain">(input == </code><code class="java keyword">null</code> <code class="java plain">|| input.length <=</code><code class="java value">1</code> <code class="java plain">) </code><code class="java keyword">return</code> 0;

int n = input.length;

int currentMax = 0;

String[] nextGreater = solution(input);

for(int i =0;i<n;i++){

String value = nextGreater[i];

if(value.equals("MAX")){

continue;

}

int nextValue =Integer.valueOf(value);

currentMax = Math.max(currentMax, nextvalue - input[i]);

}

return currentMax;

}

TimeComplexity: O(n)

Space Complexity: O(n)

 

 

 

 

 

How to fail with MicroServices

microservices

 

As we all know, microservices is the new god in the tech industry. Yes, we always have old gods and new gods. Surely microservices have been accepted by the many of the companies, without even understanding how the business will be aligned with it.

Let’s not discuss what is microservices, but we should surely discuss what not to do if you don’t want fire on your ass.Today will try to discuss few of the shortcoming which I have felt after I have[NOT]proudly redesigned the system from monolith to microservices.

  • Domain is Important, But not the same Domain For every one

We all know the domain is very important for every application.Let’s make our code closer to the real-world entity. But does the sharing of domain make sense?Often people debate about how come we can have a different domain for the same entity.For example, let’s have a Flight domain, Flight will be flight, no matter it is in search service or booking service. Flight can have different attributes in both the context.And you will never replicate these attributes.Never create a single jar of domains to share it among different services. If you have to just kill other your services.

  • How services are talking to each other

Often developers create many microservices, they all the talking to each other in exactly the same way, it has been doing if they were a monolith.Direct interaction with microservice can be dangerous, can create a bottleneck for a process. Try to design a system in such a way that one service should not be waiting because of the action from another service. Utilize the power of asynchronous request using the messaging queue or any other design.Blocking request can be a hassle. Don’t just create distributed monolith

  • Complete System Design is Important, Microservice alone cannot do anything

When you are designing the microservice, you are not designing it for fun. It will eventually be plugged in the system to complete the bigger task. So know your system design. All the constraints against which your service will be run should be known. Development of microservice can be done in the isolation, but the birth of any microservice should always be an outcome of whole system design.

  • Be Ready before you start, DevOps if your key

devops.png

You can ask yourself, why the concept of microservice in a boom these days. This is because now we have such a capability which can handle such a massive complexity. So DevOps is too important. If your DevOps is not ready to support the proper microservice architecture, never ever think to go towards microservices.You can never create a home if your basic structure is not setup first.

  • Don’t try to clean the mess of other

144158-145685

Your service is not designed to clean the work of any other service. If any service is not doing its task completely, it’s not your duty to do it, ask that service to do it. There was a very simple example which I want to share, I was consuming one of the services whose owner was sitting beside me. Few of the attributes were missing from the result of that service, so I asked the owner to provide me the missing data, but the conversation finally went in a disappointed way. The owner asks me to fill the data by myself as getting those data points were very difficult for that service. And eventually, my service ends up doing a task which was not in the context of its boundary.

  • Learn from others, but don’t ever replicate their mistakes

We often share code, when a business is trying to solve the same kind of problems they often end up using the same type of approach/code for the different problem statement. There may be a chance good chance you will solve a problem very quickly by just simple copy paste, but you never know the constraints under which that code was written. With the power of that code, your are also copying the weakness of it. Learn from others, but never accept its solution for granted.

  • Let the services to micro, not the knowledge pool 

 

shareLogo

In the last point, I have discussed how dangerous the code replication. But This point doesn’t say we should blindly learn from other services. What I want to point out here is share the knowledge of other services, either the technical findings or the business constraints. Because in the end every micro service a broken piece of a giant puzzle

  • Let the code be agile, not just the process

Often people make the process agile but forget that if your code is not agile you cannot achieve agility. Make your services loosely coupled.Each service should be independent, and there should be minimum effort even if we have to rewrite the entire service.

  • Monolith business with microservices is as bad as Monolith

“This is the way things are done here”. One of the very old statements from old timers or from the business guys. But this will never help a project. If your system is going toward microservice, itis very important your business should also reflect the same, or honor it.At the end business thinking will be reflected on your system.

  • Common decision for every service is a hazard

Since every service is designed for its own purpose, a single and common solution can be dangerous for the lifecycle of services. It is very similar to the problem of selling shoes in the two very different geographic area.

  • Frameworks as awesome, but maybe not awesome for every service

Frameworks are awesome, it will hide the complexity from the developers, and magically do a lot of the stuff. But in-house framework can be a risk to the ongoing project. If you add the in-house framework to each and every service of your, you are binding the bugs associated with the framework to every service. It even often delays the release cycles.

  • Event Sourcing, I will be another Netflix

Don’t just use any of the modern design just for the sake of using it. Understand the business requirement first. Analyse the scope of your problem in terms of the traffic and availability of the system. What I have seen people often used event sourcing even to solve the simple problem stating the reason “We will be next Netflix”.

  • Different shops, with the same warehouse

Lest assume we have 5 different shops, but all the shops using the resource from a common pool. We have 10 resources in the pool and 5 services.Ideally 2 resources for each service, but if one of the services goes greedy/faulty and consumed 8 resources.Certainly there is a resource crunch for other services. even though other services are related to service one, but it got affected because of it. Same conditions are very common whenever we are using the same Database for the different microservices.Even in normal conditions, we know that database will be the choking point in the high traffic situation. Should implement the seperate database for separate services.

  • Pool of PolyGlot can be a pool of death

This point is more in the concern of the company.But not just company is affected, even the developers are affected, as it often increases the effort in maintenance. Choosing entirely different tech stack for each service can increase the project cost, as you need the tech specialist for each tech. Sharing of tech knowledge will be limited. And often the company cannot afford many tech specialists for tech, so eventually, it can let to the dependencies on few of the forks.

  • Anonymous service is a ghost

One of the common design we can see these days is, if few of the task which is not a good fit any of the existing services, developer eventually put all these tasks in the anonymous service, where no one knows what is happing. Service with no boundary, no exact reason. I call these kinds of services as a ghost. Ghost services are dangerous, and they are often the result of poor design or to support existing business for the time being. But remember you can never get rid of the ghost, and they will haunt you from time to time.

 

All these are the points which are the concern for me, maybe true or not true for you. These can be avoided or can be tackled with different designs, but do consider them before it late for your service.

 

 

 

Print next Greatest Element for entry in an Array.

Problem

Given an array, which can have positive and negative numbers, write a code to print the next greatest element for each element. For the last number, next greater element will always be Integer.MIN.

For element, for which no greater number is present, print Integer.MIN.

Example – input array – [7,1,5,3,6,4]

Expected output – [MIN,6,6,6,MIN,MIN] .{MIN is considered as Integer.MIN}

Method to implement :


public String[] solution(int[] input);

Solution


public String[] solution(int[] input){

if(input == null || input.length <=1 ) return null;
int n = input.length;
String[] result = new String[n];
Stack<Integer> s = new Stack<>();
result[n-1] = "MIN";
s.push(input[n-1]);

for(int i = n-2;i>=0;i--){

while (!s.empty() && s.peek() < input[i]){
s.pop();
}
if(s.isEmpty()){
result[i] = "MIN";
s.push(input[i]);

}else{
result[i] = s.peek().toString();

}

}
return result;
}

Implementation