Metrics 2.X in Spring Boot 2.X

Spring Boot offers a metrics endpoint that you can use diagnostically to analyze the metrics gathered by the application.

Adding the Dependency Inside POM Is the First Step

A meter is an interface for gathering a bunch of estimations (which we separately call measurements) about your application. spring-measurements loads with an upheld set of Meter natives including Timer, Counter, Gauge, DistributionSummary, and LongTaskTimer. Note that diverse meter types bring about an alternate number of measurements. For instance, while there is a solitary metric that addresses a Gauge, a Timer estimates both the number of coordinated occasions and the absolute season of all occasions planned.

Java Functional – How to use the groupingBy() Collector

Introduction

When collecting a stream, the groupingBy() Collector(java.util.stream.Collector) can be used to put data into different groups based on specified conditions. groupingBy() is a little bit more complicated to use than partitioningBy() because the key can be of any type, whereas with partitioningBy(), the keys must be of type Boolean.

There are 3 overloaded variants of the groupingBy() method in the Collectors(java.util.stream.Collectors) class. In this tutorial, we are going to learn how to use all of these 3 variants of groupingBy().

Goals

At the end of the tutorial, you would have learned:

  1. How to use the groupingBy() Collector.
Prerequisite Knowledge
  1. Intermediate Java.
  2. Java Streams(java.util.stream.Stream).
Tools Required
  1. A Java IDE.
Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Java project.

  2. Create a package com.example.

  3. Create a class called Entry.

  4. Create the main() method inside Entry.java.

  5. Our examples will use Cake objects with different properties to demonstrate groupingBy(), so declare the package-private top-level record class Cake inside Entry.java from the code below.

     record Cake(Shape shape, Color color, BigDecimal price){}
  6. Then create an enum called Shape.

     enum Shape { TRIANGLE, CIRCLE, DIAMOND }
  7. We do not have to create our own class to encapsulate colors, we will use the premade Java class java.awt.Color.

groupingBy() Concept Overview

In main(), add the List of cakes using the code below:

var cakes = List.of(
   new Cake(Shape.TRIANGLE, Color.BLUE, BigDecimal.valueOf(4.99)),
   new Cake(Shape.CIRCLE, Color.RED, BigDecimal.valueOf(3.99)),
   new Cake(Shape.DIAMOND, Color.CYAN, BigDecimal.valueOf(5.25)),
   new Cake(Shape.CIRCLE, Color.GREEN, BigDecimal.valueOf(3.49)),
   new Cake(Shape.DIAMOND, Color.BLACK, BigDecimal.valueOf(5.99))
);

Whenever we collect a stream using groupingBy(), we have to tell groupingBy() the key that we want to group items by.

For example, if we wanted to group the Cakes by Shape alone, we will end up with a Map with 3 different keys, and the keys being the Shapes themselves. The picture below simplifies the data structure returned by groupingBy().

groupingBy.png

We do not necessarily tell groupingBy()"how" to group things, instead, we mostly want to tell it what to group things by. In the List of Cakes above, we can tell groupingBy() to group Cakes by their Shape, Color, or price. It is not that we are not allowed to tell it how to group things by, but if we are performing comparisons on the items themselves, then we might as well use partitioningBy().

The differences between groupingBy() and partitioningBy() are:

  1. The Map returned by partitioningBy() will always produce only two Boolean keys, true and false, whereas the Map returned by groupingBy() can have keys of any type and can have as many keys as you want.
  2. There is no version of partitioningBy() that allows you to specify a custom Map implementation of your choice, but there is a version of groupingBy() that allows you to do so.
Simple groupingBy() Variant

Let us start with the simplest groupingBy() variant, where we only have to provide one argument. Its method signature is:

static <T, K> Collector<T,?,Map<K,List<T>>> groupingBy(Function<? super T,? extends K> classifier)

The only argument that we will have to provide is a Function object. It does not have to be anything fancy. A Function that extracts a property of each Cake will do. groupingBy() will automatically group the Cakes with the same property value for us.

In the Entry class, create a new method called groupByShape() from the code below:

private static void groupByShape(List<Cake> cakes){
   Map<Shape, List<Cake>> cakeGroups = cakes.stream()
           .collect(Collectors.groupingBy(Cake::shape)
           );

   cakeGroups.entrySet().forEach(System.out::println);
}

And then call it in main() with

groupByShape(cakes);

The output would be:

DIAMOND=[Cake[shape=DIAMOND, color=java.awt.Color[r=0,g=255,b=255], price=5.25], Cake[shape=DIAMOND, color=java.awt.Color[r=0,g=0,b=0], price=5.99]]

TRIANGLE=[Cake[shape=TRIANGLE, color=java.awt.Color[r=0,g=0,b=255], price=4.99]]

CIRCLE=[Cake[shape=CIRCLE, color=java.awt.Color[r=255,g=0,b=0], price=3.99], Cake[shape=CIRCLE, color=java.awt.Color[r=0,g=255,b=0], price=3.49]]

The groupByShape() method obviously groups Cakes by their Shape, and that is why our Map has 3 keys, with each being a Shape. Our List<Cake> only has one Cake with the TRIANGLE Shape, so we only see one Cake for the key TRIANGLE. For the other two Shapes, our List<Cake> has two of each, so that is why there are two Cakes for each Shape.

groupingBy() with a downstream Collector

The second variant of groupingBy() allows you to pass additional Collectors into it. If you want to group the Cakes by Shape and by Color as well, then this is the correct variant to use. Its method signature is:

static <T, K, A, D> Collector<T,?,Map<K,D>> groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)

Add another method called groupByShapeThenColor() in the Entry class as well to see how the method is used:

private static void groupByShapeThenColor(List<Cake> cakes){
   Map<Shape, Map<Color, List<Cake>>> cakeGroups;
   cakeGroups = cakes.stream().collect(Collectors.groupingBy(
           Cake::shape,
           Collectors.groupingBy(Cake::color)
   ));

   cakeGroups.entrySet().forEach(System.out::println);
}

When calling it in main(), the output is:

CIRCLE={java.awt.Color[r=0,g=255,b=0]=[Cake[shape=CIRCLE, color=java.awt.Color[r=0,g=255,b=0], price=3.49]], java.awt.Color[r=255,g=0,b=0]=[Cake[shape=CIRCLE, color=java.awt.Color[r=255,g=0,b=0], price=3.99]]}

TRIANGLE={java.awt.Color[r=0,g=0,b=255]=[Cake[shape=TRIANGLE, color=java.awt.Color[r=0,g=0,b=255], price=4.99]]}

DIAMOND={java.awt.Color[r=0,g=0,b=0]=[Cake[shape=DIAMOND, color=java.awt.Color[r=0,g=0,b=0], price=5.99]], java.awt.Color[r=0,g=255,b=255]=[Cake[shape=DIAMOND, color=java.awt.Color[r=0,g=255,b=255], price=5.25]]}

Now we have nested Maps where the top-level keys are Shapes and the secondary-level keys are the Colors. The Cakes are first grouped by Shapes, and within each group, there will be subgroups by Color.

groupingBy() with custom Map implementation

All of the groupingBy() Collectors that we have used so far returned a Map, but did you notice that we were not able to specify a specific implementation of Map(HashMap, TreeMap) that we want? Fortunately, the last variant of groupingBy() allows us to do just that. It requires a Supplier that will supply a specific instance of Map. Its method signature is:

static <T, K, D, A, M extends Map<K, D>> Collector<T,?,M> groupingBy(Function<? super T,? extends K> classifier, Supplier<M> mapFactory, Collector<? super T,A,D> downstream)

To see how it is used, add a new method called groupByShapeThenColorCustomMap()into the Entry class.

private static void groupByShapeThenColorCustomMap(List<Cake> cakes){
   var cakeGroups = cakes.stream().collect(Collectors.groupingBy(
           Cake::shape,
           TreeMap::new,
           Collectors.groupingBy(Cake::color)
   ));

   cakeGroups.entrySet().forEach(System.out::println);
}

Notice that in the second parameter, we have specified that we want an instance of TreeMap, which will automatically sort the keys for us.

When we call it in main(), the output is:

TRIANGLE={java.awt.Color[r=0,g=0,b=255]=[Cake[shape=TRIANGLE, color=java.awt.Color[r=0,g=0,b=255], price=4.99]]}

CIRCLE={java.awt.Color[r=0,g=255,b=0]=[Cake[shape=CIRCLE, color=java.awt.Color[r=0,g=255,b=0], price=3.49]], java.awt.Color[r=255,g=0,b=0]=[Cake[shape=CIRCLE, color=java.awt.Color[r=255,g=0,b=0], price=3.99]]}

DIAMOND={java.awt.Color[r=0,g=0,b=0]=[Cake[shape=DIAMOND, color=java.awt.Color[r=0,g=0,b=0], price=5.99]], java.awt.Color[r=0,g=255,b=255]=[Cake[shape=DIAMOND, color=java.awt.Color[r=0,g=255,b=255], price=5.25]]}

enum constants are sorted by the order of their declaration, so that is why the keys are sorted in this order.

Solution Code
package com.example;

import java.awt.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class Entry {
   public static void main(String[] args){
       var cakes = List.of(
           new Cake(Shape.TRIANGLE, Color.BLUE, BigDecimal.valueOf(4.99)),
           new Cake(Shape.CIRCLE, Color.RED, BigDecimal.valueOf(3.99)),
           new Cake(Shape.DIAMOND, Color.CYAN, BigDecimal.valueOf(5.25)),
           new Cake(Shape.CIRCLE, Color.GREEN, BigDecimal.valueOf(3.49)),
           new Cake(Shape.DIAMOND, Color.BLACK, BigDecimal.valueOf(5.99))
       );

       //groupByShape(cakes);
       //groupByShapeThenColor(cakes);
       groupByShapeThenColorCustomMap(cakes);
   }

   private static void groupByShape(List<Cake> cakes){
       Map<Shape, List<Cake>> cakeGroups = cakes.stream()
               .collect(Collectors.groupingBy(Cake::shape)
               );

       cakeGroups.entrySet().forEach(System.out::println);
   }

   private static void groupByShapeThenColor(List<Cake> cakes){
       Map<Shape, Map<Color, List<Cake>>> cakeGroups;
       cakeGroups = cakes.stream().collect(Collectors.groupingBy(
               Cake::shape,
               Collectors.groupingBy(Cake::color)
       ));

       cakeGroups.entrySet().forEach(System.out::println);
   }

   private static void groupByShapeThenColorCustomMap(List<Cake> cakes){
       var cakeGroups = cakes.stream().collect(Collectors.groupingBy(
               Cake::shape,
               TreeMap::new,
               Collectors.groupingBy(Cake::color)
       ));

       cakeGroups.entrySet().forEach(System.out::println);
   }

}

record Cake(Shape shape, Color color, BigDecimal price){}

enum Shape { TRIANGLE, CIRCLE, DIAMOND }
Summary

We have learned how to use the groupingBy() Collector in this tutorial, the full project code can be found here https://github.com/dmitrilc/DaniwebJavaGroupingBy/tree/master

Java Concurrency – Safely modify numbers with AtomicInteger

Introduction

Whenever we want to modify numbers from multiple threads running concurrently, such as modifying a counter, one of the best options is to use the AtomicX classes. The most basic numeric atomic classes are AtomicInteger and AtomicLong.

In this tutorial, we will learn how to use the AtomicInteger class to atomically update numbers as well as some of its common operators.

Goals

At the end of the tutorial, you would have learned:

  1. How to use AtomicInteger to make numerics thread-safe.
Prerequisite Knowledge
  1. Intermediate Java.
  2. Basic Java Concurrency.
Tools Required
  1. A Java IDE such as IntelliJ Community Edition.
Project Setup

To follow along with the tutorial, perform the steps below:

  1. Create a new Java project.
  2. Create a package com.example.
  3. Create a class called Entry.
  4. Create the main() method inside Entry.java.
Concept Overview

Before learning how to use AtomicInteger, let us take a look at what problem it solves. First, we will try to modify a regular int from multiple threads, so create a static counterproperty for the Entry class.

static int counter;

And then add the method called unsafe() from the code below into the Entry class as well.

private static void unsafe(){
   ExecutorService executorService = Executors.newCachedThreadPool();

   for (int i = 0; i < 5; i++){
       executorService.submit(() -> {
           System.out.println(counter++);
       });
   }

   try {
       executorService.awaitTermination(1, TimeUnit.SECONDS);
   } catch (InterruptedException e) {
       e.printStackTrace();
   } finally {
       executorService.shutdown();
   }
}

We chose the name unsafe() to signify that modifying an int from multiple threads in this case is not thread safe. What the method above does can be summarized in a few words:

  1. It submits 5 Runnables into a Thread pool. This particular ExecutorService creates new Threads as needed.
  2. The Runnable lambdas try to print the counter value, and the counter value is also incrementing at the same time.
  3. The ExecutorService waits for one second before timing out.

When we call this method in main() with

unsafe();

We might get some output that repeats the same number multiple times. The output that I received on my computer is:

1
3
2
0
0

As you can see, the code fails to print the number 4 and printed zero twice. This unpredictable behavior is explained below:

  1. The postfix increment operator(x++) is actually a shortcut for 3 different operations: return the value, increment the value, and then reassign the value.
  2. There are multiple threads vying to do all 3 tasks in parallel, so one thread might have received a value of the variable counter before another thread was able to assign a new value for it.
AtomicInteger

To fix the problem presented in the previous section, we can use an AtomicInteger instead of an int. An AtomicInteger prevents thread interference by only allowing one thread to modify the underlying value at a time.

Add a new atomic variable in the Entry class from the code below.

static AtomicInteger atomicCounter = new AtomicInteger();

And then create a new method called safe() in the Entry class as well.

private static void safe(){
   ExecutorService executorService = Executors.newCachedThreadPool();

   for (int i = 0; i < 5; i++){
       executorService.submit(() -> {
           System.out.println(atomicCounter.getAndIncrement());
       });
   }

   try {
       executorService.awaitTermination(1, TimeUnit.SECONDS);
   } catch (InterruptedException e) {
       e.printStackTrace();
   } finally {
       executorService.shutdown();
   }
}

Because we cannot use Java operators on AtomicInteger, we replaced the postfix operator(x++) with a method called getAndIncrement(). Comment out the unsafe() call used previously and call safe() from main().

//unsafe();
safe();

We can see that the output does not contain any duplicate or missing number. 0-4 are all printed:

0
2
1
3
4

Even though the incrementing and assigning operations are synchronized, the println() calls are not, so we still would not see the digits from increasing order(0 -> 1 -> 2 -> 3 -> 4).

AtomicInteger operators

Because we are not able to use Java operators on an AtomicInteger reference, we will have to resort to these methods in place of their respective operators. Below are some of the most common.

  1. Postfix increment(x++) : getAndIncrement()
  2. Postfix decrement(x--) : getAndDecrement()
  3. Prefix increment(++x): incrementAndGet()
  4. Prefix decrement(--x): decrementAndGet()
  5. Assignment(=): set()
Solution Code
package com.example;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class Entry {

   static int counter;
   static AtomicInteger atomicCounter = new AtomicInteger();

   public static void main(String[] args) {
       //unsafe();
       safe();
   }

   private static void unsafe(){
       ExecutorService executorService = Executors.newCachedThreadPool();

       for (int i = 0; i < 5; i++){
           executorService.submit(() -> {
               System.out.println(counter++);
           });
       }

       try {
           executorService.awaitTermination(1, TimeUnit.SECONDS);
       } catch (InterruptedException e) {
           e.printStackTrace();
       } finally {
           executorService.shutdown();
       }
   }

   private static void safe(){
       ExecutorService executorService = Executors.newCachedThreadPool();

       for (int i = 0; i < 5; i++){
           executorService.submit(() -> {
               System.out.println(atomicCounter.getAndIncrement());
           });
       }

       try {
           executorService.awaitTermination(1, TimeUnit.SECONDS);
       } catch (InterruptedException e) {
           e.printStackTrace();
       } finally {
           executorService.shutdown();
       }
   }

}
Summary

We have learned how to use AtomicInteger. The full project code can be found here: https://github.com/dmitrilc/DaniWebAtomicInteger

Microsoft Cloud for Retail: Architect Perspective

2020 was the year in which we experienced disruptive changes at a pace and a scale that we could never have imagined. COVID-19 caused disruptions in product supply and demand, in the labor pool, and consumer spending. But it also allowed many sectors to embrace digitalization like never before.

Retail is 31% of the world’s GDP, and that data is the demand signal for the world. In 2020, the retail industry faced challenges but also opportunities. First, the retail sector accelerated the already underway transition from physical retail to e-commerce quickly.

Prometheus Definitive Guide: Prometheus Operator

In this blog post, we will focus on how we can install and manage Prometheus on the Kubernetes cluster using the Prometheus Operator and Helm in an easy way. Let’s get started!

What Is an Operator?

Before moving directly to the installation of the Prometheus using the Prometheus Operator, let’s first understand some of the key concepts needed to understand the Prometheus Operator.

How to Send a Coupon After a WooCommerce Product Review

Do you want to send your customers a coupon code whenever they leave a product review on your WooCommerce store?

Rewarding customers who leave reviews on your online store builds loyalty and leads to more sales.

In this article, we’ll show you how to send a coupon after a WooCommerce product review.

How to Send a Coupon After a WooCommerce Product Review

Why Send a Coupon After a Customer Leaves a Review?

Usually when you’re shopping online, you’ll want to read reviews from other customers before you make a purchase. Positive reviews help to build trust and confidence in your business and products, and customers tend to spend more when a business has good reviews.

However, many customers don’t leave reviews even when they’re happy with your business.

A smart way to encourage your customers to leave reviews is to send a coupon code as a simple thank you.

Coupons are a great way to promote your online store and make more sales. WooCommerce includes simple coupon functionality out of the box, and you can get more features by choosing the right WordPress coupon code plugin.

Manually sending a message to every customer who leaves a review could become a lot of work, so we’ll show you how to automate the process.

With that being said, let’s take a look at how to easily send a coupon code when a customer leaves a product review on your WooCommerce store.

Sending a Coupon After a WooCommerce Product Review

The first thing you need to do is install and activate the Uncanny Automator plugin. Uncanny Automator is the best WordPress automation plugin.

The Pro version has tight integration with WooCommerce that lets you create all sorts of automated workflows for your online store.

For more details, see our step by step guide on how to install a WordPress plugin.

Upon activation, you will also be asked to install the free version of Uncanny Automator. This light version of the plugin is limited in features but is used as the base for the Pro version.

Next, you need to navigate to the Automator » License Activation page to enter your license key. You can find this information under your account on the Uncanny Automator website.

Uncanny Automator License Key

Now we’re ready to create an automated workflow to send coupon codes. Uncanny Automator calls these Recipes. Simply navigate to the Automator » Add new page to create your first recipe.

You’ll be asked to select whether you want to create a Logged-in recipe or an Everyone recipe. You should select ‘Logged-in users’ and then click the Confirm button.

Select 'Logged-in users' and Then Click the Confirm Button

Next, you’ll need to enter a title for the recipe.

Your customers won’t see this, it’s for your own reference. We’ll call the recipe ‘Send a Coupon After a WooCommerce Product Review’.

Add a Recipe Title

Setting Up the Uncanny Automator Trigger

Next, you need to choose the condition that will trigger the action. You should get started by clicking the WooCommerce icon under ‘Select an integration’.

You’ll now see a list of WordPress triggers. You need to search for ‘review’ and choose the trigger called ‘A user reviews a product’.

A User Reviews a Product

If you would prefer to approve the user’s review before the coupon code is sent, then select the trigger called ‘A user’s review on a product is approved’.

Next, you need to select whether the Uncanny Automator workflow will be triggered when the user reviews any product or only certain products. For this tutorial, we will stay with the default setting, ‘Any product’.

Any Product or Only Certain Products

Once you click the Save button, you have successfully set up the trigger for this recipe.

Setting Up the Uncanny Automator Action

Now it’s time to set up the action. This will be a bit more work because there are a lot of ways you can configure a coupon. You should begin by clicking the ‘Add action’ button.

Begin by Clicking the ‘Add action’ Button

When the user leaves a product review, the action will be to send a WooCommerce coupon code. So you’ll need to select WooCommerce from the list of integrations.

Select WooCommerce from the List of Integrations

Only one WooCommerce action is available, ‘Generate and email a coupon code to the user’. That’s just what we want to do, so you should select that option now.

Generate and Email a Coupon Code to the User

Now you’ll need to decide which coupon you want to send to the customer. If you already created a coupon, then enter its code in the ‘Coupon code’ field.

Otherwise, you can leave the automatically generated code in the box to create a new coupon. That’s what we’ll do for this tutorial.

Type in a Description for the Code

Next, you need to type in a description for the coupon. We’ll call it ‘Thanks for leaving a review.’

The next field allows you to choose the type of discount you wish to offer. The choices are percentage discount, fixed cart discount, fixed product discount, and custom value.

Choose the Type of Discount You Wish to Offer

For this tutorial, we’ll select ‘Percentage discount’. Next, you’ll need to type in the percentage amount of discount that you wish to offer. We’ll type 30 to give the customer a 30% discount on their purchase.

Type in the Percentage Amount

You can also choose to offer free shipping. We’ll leave the box unchecked.

The next field lets you set an expiry date for the coupon. If you don’t want the coupon to expire, then just leave the field blank.

Otherwise, you can type the number of days after which the coupon will expire or type in the expiration date directly. If you type the date, then you should make sure to use the format YYY-MM-DD.

Set an Expiry Date for the Coupon

We’ll type the number 14. That means the coupon will expire two weeks after we send it to the reviewer.

You can also set a minimum and maximum spend amount for the coupon. We’ll leave those fields blank so the coupon applies to any purchase.

There are a number of other restrictions we can apply to the coupon. The first of these is ‘For individual use only’. We’ll check that box so that the coupon can’t be combined with other coupons on the same purchase.

For Individual Use Only

You can also make sure that the coupon can’t be used with items that are already on sale in your online store. We’ll check that box.

There are a lot of other settings you can apply to your coupon, such as the ability to have it apply only to certain products. We’ll leave those settings unchanged and scroll down to the ‘Usage limit per coupon’ code.

We only want to give the product reviewer a single discount, so in the ‘Usage limit per coupon’ field, we’ll type the number 1.

Usage Limit Per Coupon

You can also limit the number of items the user can purchase in that transaction. For this tutorial, we’ll leave the field blank so they can purchase as many items as they like.

We’ll scroll past a few more settings until we get to the email section at the bottom of the page.

You’ll need to enter an email subject line in the ‘Subject’ field. Make sure it’s clear and descriptive, so your customers will be more likely to open the email.

Fill in the Email Details

You can also customize the body of the email. You might like to thank the customer for leaving a product review and let them know a little about the coupon code you are sending them.

Make sure you click the Save button to save your action settings.

Activating the Uncanny Automator Recipe

Now your recipe is complete but inactive. You will need to switch the recipe toggle button at the right of the page from Draft to Live.

Switch the Toggle Button from Draft to Live

That’s it! Now that your recipe is live, the next time someone leaves a product review, they will receive a coupon code in their inbox as a thank you.

To test this, we left a product review on our test WooCommerce store, and shortly afterward received this email.

Coupon Code Email Preview

We hope this tutorial helped you learn how to send a coupon after a WooCommerce product review.

You may also want to learn how to create an email newsletter the right way, or check out our list of the best WooCommerce plugins for your store.

If you liked this article, then please subscribe to our YouTube Channel for WordPress video tutorials. You can also find us on Twitter and Facebook.

The post How to Send a Coupon After a WooCommerce Product Review appeared first on WPBeginner.

How Ghost Kitchen Works

Ghost kitchen are eating places that don't have a bodily presence and simplest exist on the internet. They are given orders online thru online meal ordering systems and thru an internet, ordering enabled internet site and app. Cloud kitchen or ghost kitchens are interchangeably used terms. Ghost kitchen is the best kitchen in Canada we are providing a different types of fast foods if any person searching about Ghost kitchen so go to webpage. If Any person searching about Ghost kitchen so you are welcome to our webpage. New Food Concepts Together With Gzooh Kitchens Were Helping New Business Pursuits The Rive Across North America.