Suggested Pages

Tuesday, May 26, 2015

JAX-RS POST Example

Example of Rest Service with POST method


@EJB
private DeviceRepository deviceRepository;

@EJB
private ContactRepository contactRepository;


@Path(value = "/devices/{deviceID}/contacts")
@POST
@Consumes({ MediaType.APPLICATION_JSON })
public ContactResponse saveContact(@PathParam(value = "deviceID") String deviceID, ContactRequest contactRequest) {
  try {
    Device device= deviceRepository.findById(deviceID);
    Contact contact=createContact(contactRequest,device);
    contact=contactRepository.save(contact)
    return createResponse(contact);
  } catch (Exception e) {
    throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
  } 
 }

JPA Example of Named Query

Contact.java



@NamedQueries(value = @NamedQuery(name = "findContactByMail", query = "SELECT c FROM Contact c WHERE c.mail= :mail AND c.location= :location"))
@Entity
@Table(name = "CONTACT")
public class Contact {

 @Id
 @Column(name = "ID")
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;

 @Column(name = "MAIL")
 private String mail;

 @Column(name = "LOCATION")
 private String location;

        ....
}

Client.java

   
   @PersistenceContext
   private EntityManager entityManager;


   public Contact findContactByMail(String mail, String location){

     TypedQuery findContactByMail = entityManager.createNamedQuery("findContactByMail",Contact.class);
     findContactByMail.setParameter("mail", mail);
     findContactByMail.setParameter("location", location);

       try {
            return findContactByMail.getSingleResult();
       } 
       catch (NoResultException e) {
            return null;
       }
    }
    ....
}

JPA multiple Unique Constraint

BeanExample



@Entity
@Table(name = "BEAN_TABLE", uniqueConstraints = @UniqueConstraint(columnNames = { "FIRST_COLUMN", "SECOND_COLUMN" }))
public class BeanExample {

 
 private static final long serialVersionUID = 1L;

 @Id
 @Column(name = "ID")
 private String id = UUID.randomUUID().toString();

 
 @Column(name="FIRST_COLUMN")
 private String firstColumn;


 @Column(name="SECOND_COLUMN")
 private String secondColumn;

 ....
}

Wednesday, May 20, 2015

Design Pattern Builder - Example

Notification.java


import java.util.Date;

/**
 * The Class Notification.
 */
public class Notification {

 /** The system. */
 int SYSTEM = 1;

 /** The application. */
 int APPLICATION = 2;

 /** The builder. */
 private Builder builder;

 /**
  * Instantiates a new notification.
  * 
  * @param builder
  *            the builder
  */
 private Notification(Builder builder) {
  this.builder = builder;
 }

 /**
  * Gets the code.
  * 
  * @return the code
  */
 public int getCode() {
  return builder.code;
 }

 /**
  * Gets the priority.
  * 
  * @return the priority
  */
 public int getPriority() {
  return builder.priority;
 }

 /**
  * Gets the info.
  * 
  * @return the info
  */
 public String getInfo() {
  return builder.info;
 }

 /**
  * Gets the short description.
  * 
  * @return the short description
  */
 public String getShortDescription() {
  return builder.shortDescription;
 }

 /**
  * Gets the long description.
  * 
  * @return the long description
  */
 public String getLongDescription() {
  return builder.longDescription;
 }

 /**
  * Gets the date.
  * 
  * @return the date
  */
 public Date getDate() {
  return builder.date;
 }

 /**
  * The Class Builder.
  */
 static class Builder {

  /** The date. */
  private Date date = new Date();

  /** The long description. */
  private String longDescription;

  /** The short description. */
  private String shortDescription;

  /** The info. */
  private String info;

  /** The priority. */
  private int priority = 0;

  /** The code. */
  private final int code;

  /**
   * Instantiates a new builder.
   * 
   * @param code
   *            the code
   */
  public Builder(int code) {
   this.code = code;
  }

  /**
   * Sets the short description.
   * 
   * @param shortDescription
   *            the short description
   * @return the builder
   */
  public Builder setShortDescription(String shortDescription) {
   this.shortDescription = shortDescription;
   return this;
  }

  /**
   * Sets the date.
   * 
   * @param date
   *            the date
   * @return the builder
   */
  public Builder setDate(Date date) {
   this.date = date;
   return this;
  }

  /**
   * Sets the info.
   * 
   * @param info
   *            the info
   * @return the builder
   */
  public Builder setInfo(String info) {
   this.info = info;
   return this;
  }

  /**
   * Sets the long description.
   * 
   * @param longDescription
   *            the long description
   * @return the builder
   */
  public Builder setLongDescription(String longDescription) {
   this.longDescription = longDescription;
   return this;
  }

  /**
   * Sets the priority.
   * 
   * @param priority
   *            the priority
   * @return the builder
   */
  public Builder setPriority(int priority) {
   this.priority = priority;
   return this;
  }
  
   /**
   * Builds the.
   *
   * @return the notification
   */
  public Notification build() {
   Notification notification = new Notification(this);
   return notification;
  }

 }
}

Thursday, April 30, 2015

Inject Stateless EJB in a Web Listener - Example

ParentRepository.java


package com.javablog.entity;

import javax.ejb.Local;

@Local
public interface ParentRepository {

void save(Parent parent);

}

ParentRepositoryBean.java


package com.javablog.entity;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Stateless(name="ParentRepositoryBean")
public class ParentRepositoryBean implements ParentRepository {

 @PersistenceContext(name="exampleUnit")
 private EntityManager entityManager;
 
 
 @Override
 public void save(Parent parent){
  entityManager.persist(parent);
 }
}

MyContextListener.java


package com.javablog.entity;

import javax.ejb.EJB;
import javax.servlet.ServletContextEvent;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyContextListener implements javax.servlet.ServletContextListener {
 
 @EJB 
 private ParentRepository parentRepository;
 
 public void contextInitialized(ServletContextEvent sce) {
  Parent parent = new Parent();
  parent.setName("John");
  parent.setId(1);
  parentRepository.save(parent);
 }

 public void contextDestroyed(ServletContextEvent sce) {
 }
}

JBoss WildflyTransactions Logging

In this post I only want to give an advice to developers who want to trace transactions on JBoss Wildfly.

Activate a logger category with the finest level on the following package:

  • com.arjuna.ats.jta
  • org.hibernate
  • org.jboss.as.ejb3.tx

Tuesday, April 28, 2015

Bridge Design Pattern

Bridge Design Pattern tells : decouple an Abstraction from its Implementation so that the two can vary independently.

At a first time this statement could suggest that the term Implementation refers to the concept of Concreate Class and the term Abstraction refers to a generic Interface.

Actually the concept of Implementation has nothing to do with the Subclassing concept. Implementation refers to one or more Components that an Abstraction uses to implement itself. In this way we are talking about composition, not inheritance.

The Bridge Design Pattern suggests to consider an Abstraction has a concept that may have different implementations. Therefore you should design an Implementation as an extention point: an Interface with a different class hierarchy.

As you can see from this UML Diagramm taken from Wikipedia that describes Bridge Design Pattern:

  • Abstraction is in a class hierarchy different from the Implementation hierarchy;
  • The bridge from these two hierarchies is made by Composition

The essence of the Bridge Design Pattern is in the Open-Closed Principle: open for extension, but closed for modification. You can evolve the abstraction indipendently from its "body" (the implementation). In other words you are designing the domain with this approach:

  • Identify concepts: Abstraction
  • Identify concepts that are implementation of Abstraction
  • Let an Abstraction uses Implementation to build itself

Thursday, April 23, 2015

Spring Data Specification Example

In this post i write the java code to make a simple query ( get a User by name) using Spring Data with JPA.

Step1: Create the entity User.java

User.java

package com.simonefolinojavablog;

@Entity
public class User{
 
   @Id
   private String id;

   @Column
   private String name;
    ...
}   

Step2: Create the static metamodel (User_.java) for the entity User

User_.java

package com.simonefolinojavablog;

@StaticMetamodel(User.class)
public class User_ {
 

  public static volatile SingularAttribute<User, String> id;

  public static volatile SingularAttribute<User, String> name;
...
}   

Step3: Create the specification to use for the query

UserSpecifications.java

package com.simonefolinojavablog;


import org.springframework.data.jpa.domain.Specification;


public class UserSpecifications {

 
 public static <T extends User> Specification<T> userNameIs(final User user) {
  return new Specification<T>() {
   @Override
   public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
    return cb.equals(root.<String> get(User_.name), user.getName());
   }
  };
 }

Step4: Create the repository for the entity User

UserRepository.java

package com.simonefolinojavablog;

public interface UserRepository extends PagingAndSortingRepository<User, String>, 
  JpaSpecificationExecutor<User>, JpaRepository<User, String> {

}


Step5: Use the previous components to build the service method FindByName

ExampleTest .java

import static org.springframework.data.jpa.domain.Specifications.where;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.Specifications


public class ExampleTest {


private UserRepository  userRepository;



public void User findByName(User user){

Specification<User> userNameIs= UserSpecifications.<User> userNameIs(user);
       Specifications<User> whereconditions = where(userNameIs);
       return userRepository.findOne(userIdIs);
}

}

Wednesday, April 22, 2015

@StaticMetamodel is null

A common problem is the situation when you have a Static Metamodel attribute with NULL value. During a query that makes use of the SingularAttribute you can have a NullPointerExcepton

One of the most common problem is that the Entity class and the StaticMetamodel class must be in the same package.

In the following example User.java must be in the same package of User_.java.

User_.java

package com.simonefolinojavablog;

@StaticMetamodel(User.class)
public class User_ {
 

 public static volatile SingularAttribute id;
...
}   

]]>

Monday, April 20, 2015

EJB with Spring Data Repository - Integration

In this post we are going see a very simple integration between a J2EE application and the Spring Data Framework.
Let us suppose to have the persistence layer written with Spring Data and we want to reuse the Spring Data Repository into a j2ee environment, for example in a Stateless EJB.
We can use the class JpaRepositoryFactory as shown below:
UserRepository.java

package com.simonefolinojavablog;

interface UserRepository extends Repository<User, Long> {
  ...
}
   

RepositoryAdapterBean.java

package com.simonefolinojavablog;

import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;

@Stateless(name="RepositoryAdapter")
public class RepositoryAdapterBean implements RepositoryAdapter{
  ...

 
  @PersistenceContext
  EntityManager entityManager;

  public User find(String userName){
       JpaRepositoryFactory jpaRepositoryFactory=new JpaRepositoryFactory(entityManager);
       UserRepository repository = jpaRepositoryFactory.getRepository(UserRepository.class);
       return repository.findOne(userName);

  }
}
   


You can use JpaRepositoryFactory with the EntityManager to create the UserRepository and make a reuse of all Spring Data components of the persistence layer.

Wednesday, April 15, 2015

Spring Rollback

Let's us suppose to have a transaction with a Declarative transaction management into Spring Framework and you are in the situation where an unchecked exception can be thrown.

Unless of particular configurations Spring makes a rollback of the transaction only if an uncaught exception arrives to the transactional proxy.

If you catch that exception (for logging purpose), the transaction does not roll back automatically, you can make three possible actions:

  • Rethrow the exception ( the unchecked exception);
  • Throw a new checked application exception marked to cause rollback: @Transactional(rollbackFor = YourException.class);
  • Rollback manually: sessionContext.setRollbackOnly().

Suggested Posts:

Tuesday, April 14, 2015

EntityManager FIND vs GETREFERENCE

The main difference between find and get methods of EntityManager is that:
  • EntityManager find: return an object according to the fetch policy.
  • EntityManager getReference: return an hollow object. This object is lazy initialized, it only has the primary key populated.

The main difference is that EntityManager#getReference method is useful in the situation you need only the primary key of the requested object. An possible example is when you have to use the hollow object as part of an insert statement where only the reference of that object is useful.

Recipient List - Integration Pattern (Router)

In a past post i spoke about an important integration pattern: Dynamic Router. This post instead deals with a different integration pattern called Recipient List

The Recipient List answers to the problem: how can i dispatch messages to a list of recipients instead of sending to all recipients?

This pattern tells that you have to consider two distinct process moments:

  • Inspecting messages to know the list of recipients
  • Iterates over the known list of recipients to send the messages

This implies that each participant is attached to the Recipient List component with a different Recipient Channel and that the Recipient List component has the knowledge of all recipients.

A variant of this component is the Dynamic Recipient List that use the same mechanism of Dynamic router to be notified when a new participants is interested on receiving messages.

Dynamic Router - Integration Pattern (Router)

In the following post I speak about one of the most important integration pattern: Dynamic Router

The Dynamic Router is a specialization of a Router component.

It is responsible for dispatching a message from an input channel to an output channel based on rules that may change over time.

Dynamic Router differs from Simple Router because its aim is to decouple the router component from the knowledge of the recipients.

Dynamic Router is aware of the recipients not at startup time but via a mechanisms of registration/de-registration of recipients. through a special channel called Control Channel. Each participants send a control message over the Control Channel announcing its partecipation and its preference. The Dynamic router saves these preferences into an internal database.

When an incoming message arrives, The Dynamic Router takes in consideration the message content and the preferences of its participants before dispatching the message to the most indicated recipient; but it only send the message to one recipient.

Suggested Posts:

Monday, April 13, 2015

Spring Hateoas Example


Spring Hateoas Example



In the following snippets of code you can see an example of Rest Endpoint using the Spring Hateoas framework.

This post aims to only show a runnable example giving to readers the possibility to be introduced quickly to a new argument.

BookController.java

package com.simonefolinojavablog;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/book")
public class BookController {

 @Autowired
 private BookRepository bookRepository;

 @RequestMapping(value = "/{id}", method = RequestMethod.GET)
 public @ResponseBody BookResource show(@PathVariable String id) {
  Book book = bookRepository.getBook(id);
  BookResourceAssembler bookResourceMapper=new BookResourceAssembler(getClass(), BookResource.class);
  BookResource resource = bookResourceMapper.toResource(book);
  return resource;
 }

}

BookResource.java


package com.simonefolinojavablog;

import org.springframework.hateoas.ResourceSupport;

/**
 * The Class BookResource.
 */
public class BookResource extends ResourceSupport {

 /** The name. */
 private String name;

 /**
  * Sets the name.
  * 
  * @param name
  *            the new name
  */
 public void setName(String name) {
  this.name = name;
 }

 /**
  * Gets the name.
  * 
  * @return the name
  */
 public String getName() {
  return name;
 }

}
  

BookResourceAssembler.java



package com.simonefolinojavablog;

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;

import java.util.List;

import org.springframework.hateoas.mvc.ResourceAssemblerSupport;

/**
 * The Class BookResourceMapper.
 */
public class BookResourceAssembler extends ResourceAssemblerSupport<Book, BookResource> {

 public BookResourceAssembler(Class<?> controllerClass, Class<BookResource> resourceType) {
  super(controllerClass, resourceType);
 }

 
 public BookResource toResource(Book entity) {
  BookResource resource = createResourceWithId(entity.getId(), entity);
  resource.add(linkTo(methodOn(AuthorController.class).show(entity.getAuthor().getId())).withRel("author"));
  resource.setName(entity.getName());
  return resource;
 }

 /* (non-Javadoc)
  * @see org.springframework.hateoas.mvc.ResourceAssemblerSupport#toResources(java.lang.Iterable)
  */
 @Override
 public List<BookResource> toResources(Iterable<? extends Book> entities) {
  return super.toResources(entities);
 }

}

AuthorController.java


package com.simonefolinojavablog;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * The Class AuthorController.
 */
@Controller
@RequestMapping("/author")
public class AuthorController {

 /** The author repository. */
 @Autowired
 private BookRepository bookRepository;

 /**
  * Show.
  *
  * @param authorId the author id
  * @return the http entity
  */
 @RequestMapping(value = "/{authorId}", method = RequestMethod.GET)
 public HttpEntity show(@PathVariable String authorId) {
  Author author = bookRepository.getAuthor(authorId);
  AuthorAssembler authorAssembler = new AuthorAssembler(AuthorController.class, AuthorResource.class);
  AuthorResource resource = authorAssembler.toResource(author);
  return new HttpEntity(resource);
 }

}

  

mvc-config.xml



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
 xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-3.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">


 
 <context:component-scan base-package="com.simonefolinojavablog" />

 <bean
  class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
  <property name="messageConverters">
   <list>
    <ref bean="jsonConverter" />
   </list>
  </property>
 </bean>



 <bean id="jsonConverter"
  class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
  <property name="supportedMediaTypes" value="application/json" />
  <property name="objectMapper" ref="jacksonObjectMapper" />
 </bean>

 <bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />

 <bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
  factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" />

 <bean
  class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="targetObject" ref="jacksonSerializationConfig" />
  <property name="targetMethod" value="setSerializationInclusion" />
  <property name="arguments">
   <list>
    <value type="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion">NON_NULL</value>
   </list>
  </property>
 </bean>
 
 

</beans>

Invoke Rest Endpoint

If you invoke on localhost your endpoint using the following uri http://localhost:8080/hateoas-example/book/1 you get the book resource that has identifier "1".


{"links":[{"rel":"self","href":"http://localhost:8080/hateoas-example/book/1","variables":[],"templated":false,"variableNames":[]},{"rel":"author","href":"http://localhost:8080/hateoas-example/author/1","variables":[],"templated":false,"variableNames":[]}],"name":"Never Ending Story","id":{"rel":"self","href":"http://localhost:8080/hateoas-example/book/1","variables":[],"templated":false,"variableNames":[]}}

If you analyze the following json result, you can see that the resource "Book" has two attributes ( id, name) and a collection of links. In the links sections there is a reference to another resource "Author" that is available at the address http://localhost:8080/hateoas-example/author/1

BroadcastReceiver Android Example


BroadcastReceiver Android Example



In the following snippets of code you can see an example of BroadcastReceiver. A BroadcastReceiver is a component that acts as listener of of events that could be publish by a component that acts as a Publisher. In the example I use the Context as a publisher.

Step-1: Create a class that extends BroadcastReceiver

CommandReceiver


public class CommandReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
  
                String action = intent.getAction();

                if(action.equals(Command.SHOW)){
                   String textMessage=intent.getStringExtra(Command.VALUE);
                   Toast.makeText(context,textMessage, Toast.LENGTH_SHORT).show();
                }
              
 }
}   
   
]]>

Command.java


public interface Command {

    public static final String SHOW="SHOW";

    public static final String VALUE="VALUE";

}
  

Step-2: Declare the receiver int AndroidManifest.xml

AndroidManifest.xml


      <receiver
            android:name="package.CommandReceiver "
            android:enabled="true"
            android:exported="false" >
        </receiver>
  

Step-3: Register the receiver in your Activity

ActivityExample


public class ActivityExample extends Activity {

 private CommandReceiver commandReceiver;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
                commandReceiver=new CommandReceiver();
         registerReceiver(commandReceiver, new IntentFilter(Command.SHOW));
 }


 @Override
 protected void onDestroy() {
  super.onDestroy();
  if(commandReceiver!= null) {
      unregisterReceiver(commandReceiver);
  }
 }
}
  

Step-4: Publish the Intent

Publisher Example

  
          Intent event = new Intent(Command.SHOW);
   event.putExtra(Command.VALUE, "MESSAGE");
   Context applicationContext = getApplicationContext();
   applicationContext.sendBroadcast(event);

Saturday, February 28, 2015

Java Concurrent - CountDownLatch

In this post we are going to see an example of usage of the class CountDownLatch. A tipical scenario in which it may be useful to use CounDownLatch, is the that shown below.

Example

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;


/**
 * The Class Example.
 */
public class Example {

 /**
  * The main method.
  * 
  * @param args
  *            the arguments
  */
 public static void main(String[] args) {

  Race race = new Race(2);
  race.start();
 }

 /**
  * The Class Runner.
  */
 static class Runner {

  /** The count down latch. */
  private CountDownLatch countDownLatch;

  /**
   * Instantiates a new runner.
   * 
   * @param countDownLatch
   *            the count down latch
   */
  public Runner(CountDownLatch countDownLatch) {
   this.countDownLatch = countDownLatch;
  }

  /**
   * Go.
   */
  public void go() {
   new Thread() {
    public void run() {
     try {
      System.out.println("Running..." + Thread.currentThread().getName());
      Thread.sleep((long) (Math.random() * 10));
     } catch (InterruptedException e) {
     }
     countDownLatch.countDown();
     System.out.println("End of running " + Thread.currentThread().getName());
    };
   }.start();
  }
 }

 
 /**
  * The Class Race.
  */
 static class Race {
  
  /** The count down latch. */
  private CountDownLatch countDownLatch;
  
  /** The runners. */
  private List<Runner> runners = new ArrayList<Runner>();

  
  
  /**
   * Instantiates a new race.
   *
   * @param numOfPartecipans the num of partecipans
   */
  public Race(int numOfPartecipans) {
   countDownLatch = new CountDownLatch(numOfPartecipans);
   for (int i = 0; i < numOfPartecipans; i++) {
    runners.add(new Runner(countDownLatch));
   }
  }

  /**
   * Start.
   */
  public void start() {
   for (Runner runner : runners) {
    runner.go();
   }
   waitOnFinishLine();
  }

  /**
   * Wait on finish line.
   */
  private void waitOnFinishLine() {
   try {
    countDownLatch.await();
   } catch (InterruptedException e) {
   }
   System.out.println("Race ended");
  }

  
  /**
   * Gets the runners.
   *
   * @return the runners
   */
  List<Runner> getRunners() {
   return runners;
  }

 }

}


Suppose that you have a race with some partecipants and you have to print the result of the race at the exact moment when the last runner arrives at the finishing line.
CountDownLatch allows you to synchronized the two involved thread types: - The thread that is responsible of waiting for the termination of the race. - The threads that design each partecipant to the race.
CountDownLatch is initialized with an integer that describes the number of runners in the race. As you can see each "Runner object" makes use of a "Thread ", that makes use of the method CountDownLatch#countDown() , while the "Race object" ( that runs in the main thread) uses the method CountDownLatch#await().
The main thread is blocked on the method CountDownLatch#await(). until the last Runner completes the run and invokes the method CountDownLatch#countDown().
This example is very easy and shows how to use CountDownLatch in order to allow a thread (generally a Consumer Thread) to expect that other threads (generally Producer Thread) perform particular operation.
In a wider consideration, the totality of the Runner threads represents the real Producer.

Suggested Pages