Thursday, October 15, 2015

The Adapter Design pattern

I was reading a post from Martin Fowler titled “RequiredInterface” a couple of days ago. In his post he talks about cases, where client applications define a required interface, to which potential suppliers have to adjust in order to interact with them. Later in the article, he discusses scenarios where two components were developed independently and how the adapter pattern can be used for them to work together. So I thought, why not create a short tutorial on the adapter pattern!

The Adapter design pattern is of the structural family and allows two incompatible interfaces to work together without changing their internal structure. It is used frequently with existing code, where the necessary functionality exists but the interfaces cannot work together. The adapter pattern wraps the interface and provides another one which is compatible. It is easy to imagine how the pattern works, if we take as a metaphor the electrical outlet plugs and how adapters can be used to connect our electrical devices  when traveling to countries which use different outlet types from our own. 

To provide an example of the adapter pattern implementation, we will use a randomizer and its potential client. A randomizer is a robot which takes as input a number and it returns this specific amount of random numbers in the range of 1-10. A client wishes to receive such numbers from the randomizer and print them. However, the client requires to receive the numbers in the form of a list. A randomizer robot is available, but since it is a bit old, it returns the random numbers in an array. Adapter pattern to the rescue! 

Admittedly this example is a bit naive and “stretched” but I believe it delivers the message on the motivations and implementation approach of the adapter design pattern.


Let's start by the client of our application:
package com.tasosmartidis.design_patterns_tutorial.adapter;

public class RandomizerClient {

    RandomizerRequiredAbstract requiredRandomizer;
    
    public RandomizerClient(RandomizerRequiredAbstract requiredRandomizer) {
        this.requiredRandomizer = requiredRandomizer;
    }
    
    // Print out the number of number of random digits indicated
    public void printRandomNumbers(int number) {
        System.out.println(requiredRandomizer.generateRandomNumbers(number));
    }
}

The RandomizerRequiredAbstract, is an abstract class with a single abstract method signature, to make sure that the client receives the services in the way it requires. The source code of this class is:
package com.tasosmartidis.design_patterns_tutorial.adapter;

import java.util.List;

public abstract class RandomizerRequiredAbstract {

    // The method signature as required by the client
    public abstract List<Integer> generateRandomNumbers(int number);
}

Now let's see our old randomizer which provides the functionality but not in the format required by the client:
package com.tasosmartidis.design_patterns_tutorial.adapter;

import java.util.Random;

public class Randomizer {

    // Our randomizer receives as input the number of random digits to generate, and returns them as an array.
    public Integer[] generateRandomNumbers(int number) {
        Integer[] randomNumbers= new Integer[number];
        
        if(number<1 || number >10000)
            throw new RuntimeException("you need to provide input in range 1-10000");
        else {
            for(int i=0; i<number;i++){
                randomNumbers[i] = new Random().nextInt(10);
            }
            
            return randomNumbers;
        }           
    }
}

The adapter class will use the functionality of the old randomizer and will adjust to make it compatible with the requirements of the client:
package com.tasosmartidis.design_patterns_tutorial.adapter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class RandomizerAdapter extends RandomizerRequiredAbstract {

    Randomizer randomizer;
    
    public RandomizerAdapter(Randomizer newRandomizer) {
        this.randomizer = newRandomizer;
    }
    
    // Our randomizer adapter, uses the old randomizer that returns random 
   // numbers in an array and adapts its output to a list, so
  // that it realizes the client's requirements
    @Override
    public List<Integer> generateRandomNumbers(int number) {
        return new ArrayList<Integer>(Arrays.asList(randomizer.generateRandomNumbers(number)));
    }
}

And now we are ready to run our application and see how the client gets its functionality from the old randomizer through the adapter:
package com.tasosmartidis.design_patterns_tutorial.adapter;

public class AdapterDemo {

    public static void main(String[] args) {
        
        // The old randomizer 
        Randomizer oldRandomizer = new Randomizer();
        
        // The adapter for the randomizer
        RandomizerAdapter adapterRandomizer = new RandomizerAdapter(oldRandomizer);
        
        // Our client that needs the randomizer services
        RandomizerClient client =  new RandomizerClient(adapterRandomizer);
        
        // Print the random numbers indicated
        client.printRandomNumbers(8);       
    }
}

Running the application would just print the list of 8 random numbers as requested in the source code above. The project is available in my GitHub. This concludes our brief tutorial on the adapter design pattern. Stay tuned and more to come!



Sunday, October 11, 2015

The Factory Design pattern

The first in our series of design pattern tutorials will be the factory pattern, which is one of the most used design patterns. The factory pattern is a creational pattern which allows the construction of objects without specifying the exact class of the object to be created at design time. During runtime, the appropriate class is selected for creating the object based on the context. The factory pattern allows looser coupling by removing the selection code to a specified class - “the factory”.

We are going to see an implementation of the factory pattern using Java and also how the "factory" class wouldn't be necessary with the use of Java 8.

To showcase with a simple example how the factory pattern could be used, let’s imagine we have a jukebox and the vinyl record is selected based on the button pressed by the user. The interface is the vinyl record, and specifies a single method ‘playMusic’. We have different vinyl records that implement the interface. During runtime, the factory object selects which object (vinyl) to instantiate in order to play music.

The UML class diagram for our project is presented in the figure below:

We start with the VinylRecord interface which will allow us the abstraction in order to select its implementation at runtime:
package com.tasosmartidis.design_patterns_tutorial.observer;

public interface VinylRecord {

    public void playMusic();
}

Next, we will provide the concrete implementations of the VinylRecord for Jazz fans:
package com.tasosmartidis.design_patterns_tutorial.observer;

public class JazzVinyl implements VinylRecord {

    public void playMusic() {
        System.out.println("Playing some smooth jazz...");
        
    }
}

and for Rock & Roll fans:
package com.tasosmartidis.design_patterns_tutorial.observer;

public class RockNRollVinyl implements VinylRecord {

    public void playMusic() {
        System.out.println("Rock n Rolling baby...");
        
    }
}

Now that we have our implementations of the VinylRecord, lets create a factory class which will create the appropriate implementation based on context:
package com.tasosmartidis.design_patterns_tutorial.observer;

public class JukeBox {
    
    public VinylRecord pickVinyl(Integer chosenVinyl) {
        
        switch(chosenVinyl){        
        case 1:
            return new JazzVinyl();
        case 2:
            return new RockNRollVinyl();
        default:
            return null;
        }
    }
}

Finally, we are ready to see our factory pattern implementation in action. We have a simple main method which presents the user with a set of options and waits to receive a valid choice to play some music:
package com.tasosmartidis.design_patterns_tutorial.observer;

import java.util.Scanner;

public class FactoryDemo {

    public static void main(String[] args) {
        JukeBox jukeBox = new JukeBox();
        VinylRecord vinyl;
        
        // The jukebox is in a bar and waits 
        // for the selection of music to play
        System.out.println("What would you like to hear?");
        System.out.println("1. Jazz");
        System.out.println("2. Rock & Roll");
        
        // Get the selection of the user
        Scanner inputReader = new Scanner(System.in);
        boolean selectionMade = false;
        while(!selectionMade) {
            Integer selection = inputReader.nextInt();
            
            if(selection.equals(1) || selection.equals(2)){
                vinyl = jukeBox.pickVinyl(selection);
                selectionMade = true;
                
                if(vinyl!=null) {
                    // Play the song!
                    vinyl.playMusic();
                }else {
                    throw new IllegalArgumentException("Not a valid choice!");
                }
            }
            else 
                System.out.println("You have to press 1 or 2!");
        }
        inputReader.close();        
    }
}

Running the above demo app would look something like this:


And we are done! A simple example to demonstrate the use of the factory pattern. But as we said in the previous post, design patterns do not take into consideration language specifics. How use of Java8 would affect the implementation of the factory design pattern?

We could implement the factory pattern as shown in the main class below:
package com.tasosmartidis.design_patterns_tutorial.observer;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.function.Supplier;

public class FactoryJava8Demo {
    
    // A map with the constructors of the VinylRecords implementations
    final static Map<Integer,Supplier<VinylRecord>> implementations = 
                    new HashMap<Integer, Supplier<VinylRecord>>();

    public static void main(String[] args) {
        // Add the implementations we have
        implementations.put(1,JazzVinyl::new);
        implementations.put(2,RockNRollVinyl::new);
        
        VinylRecord vinyl;
        
        // The jukebox is in a bar and waits 
        // for the selection of music to play
        System.out.println("What would you like to hear?");
        System.out.println("1. Jazz");
        System.out.println("2. Rock & Roll");
        
        // Get the selection of the user
        Scanner inputReader = new Scanner(System.in);
        boolean selectionMade = false;
        while(!selectionMade) {
            Integer selection = inputReader.nextInt();
            
            if(selection.equals(1) || selection.equals(2)){
                vinyl = createVinyl(selection);
                selectionMade = true;
                // Play the song!
                vinyl.playMusic();
            }
            else 
                System.out.println("You have to press 1 or 2!");
        }
        inputReader.close();

    }
    
    public static VinylRecord createVinyl(Integer selection) {
        Supplier<VinylRecord> vinylSelected = implementations.get(selection);
        if(vinylSelected!=null) 
            return vinylSelected.get();
        else 
            throw new IllegalArgumentException("Not a valid choice!");
    }
}

We have to note though, that this implementation with Java 8 wouldn't necessarily be cleaner or scale better in more complex scenarios, such as having more parameters for the initialization of the implementation classes. You can find the source code in GitHub.

That was the first in the upcoming series of design patterns, so keep in touch!

Saturday, October 10, 2015

Design Patterns

This post serves as an introduction on a series of tutorials I plan to do on design patterns. Design patterns, in software engineering, are “best practices” solutions to common challenges faced when designing software. The design patterns are not packaged designs, ready to be developed and compiled but rather instructions or suggestions on the best approach to design applications using proven paradigms.

The design patterns became widely popular among developers thanks to the "Design Patterns: Elements of Reusable Object-Oriented Software" book, authored by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides (also known as "Gang of Four").

Design patterns are usually placed under one of the following categories:
  • Creational, which concern patterns used to decouple construction of objects from their implementing system
  • Structural, where patterns use many disparate objects to compose structures with new and greater functionalities
  • Behavioral, which are patterns mainly concerned with relationships, functionalities and communication between objects
Use of design patterns provides many advantages when designing software. They provide a common terminology, meaning that with only a pattern name a software developer can communicate a whole design approach to colleagues. Additionally, they result into better software designs and applications because they give tested and proven recipes used by many. Also they facilitate faster development because the design following such patterns is usually clear, reusable and maintainable.

Of course use of design patterns are not a panacea or an insurance for quality design. Design patterns must be selected and used in the appropriate context and for the specific problem. Trying to fit as much design patterns as possible in the design of an application can result to unnecessary complexity and bad design. Also, design patterns do not take into consideration the use of specific languages, meaning that a pattern could be simplified or eliminated by using features of programming languages and paradigms (e.g., functional programming). As we will see in future tutorials I plan to do for design patterns, the implementation of patterns with Java 8 can be quite different by implementation with its prior versions.

As mentioned earlier I plan to post design patterns in my blog in the near future, but there are already a lot of great resources for design patterns, and below are some of my favorite:

Sunday, October 4, 2015

On innovative applications, networking and presenting

I was recently in an R&D event, where representatives from companies, universities, research centers and industries got together and discussed business challenges, emerging technologies and innovative applications to overcome these challenges. It was a very interesting event from many perspectives and I personally got insights on different aspects. I will discuss here about some of them, and specifically, innovative applications of the near future, the art of networking and (things that get in the way of) giving engaging presentations. I have to be abstract about the innovations since I am not allowed to discuss details of the specific use cases and applications.

On innovative applications, a number of good ideas were pitched, in diverse business and societal domains, motivated by various challenges. Many different technologies and applications were proposed for solutions but nearly all of them had (in my opinion) a common underlying workflow and made one thing obvious: data is king.

Some examples of the applications discussed were:
  • Drug testing based on simulations and 3D models of cells
  • Elderly watch and assisted living via ambient intelligence
  • Real-time creation of 3D maps of environment during safe and rescue operations
  • Early detection of deteriorating machines in manufacturing
  • Optimized and collaborative transportation of goods and services
  • Prevention of currently untreatable mental diseases
  • 3D digital pathology using digital replicas of human organs for monitoring and diagnosis
  • Digitalized management and monitoring of electricity production/consumption based on M2M
As I see it, all the above applications aim to facilitate  knowledge based decisions and actions. Almost all of them opt for real-time input-interpretation-action, meaning, they aim to respond to events as soon as they happen or even know how things will be and respond to that. This predictive approach is especially related to the “prevent over fix” of the applications such as elderly care, deteriorating machines and untreatable mental diseases. Building on the knowledge based decisions and actions different projects get more specialized to facilitate increased safety (i.e., development of drugs, elderly care) and situational awareness (i.e. safe and rescue operations) or optimized utilization of resources for decreased costs and waste (i.e., manufacturing, transportation, utilities & power).

 And technically on a (quite) high level, the applications had a similar workflow:
  1. Gather data from multiple sources (volunteered, observed or deduced)
  2. Communicate the data (where semantics and integration are often challenging)
  3. Build models based on the data and vice versa consolidate the data into models
  4. Experiment on them and make sense out of them
  5. Plan and act based on the information
 Again there are many technical and non-technical issues to be overcomed for many of the above applications, such as legislatory framework and standardization, but in general, very interesting stuff!

On networking, I believe things are simple. Be active and interested. Move, greet, smile, introduce yourself and other people. Do not spend a second not talking to someone. But be genuinely interested. These events are very good opportunities. Most people there have things to say. They are people with (more or less) common interests, most are individuals who take action and are ambitious. There are many opportunities to learn from others, don’t waste any opportunities. But it is important to really do listen to them. Sometimes it feels easy to just nod and smile when someone is talking to you. This can happen because your interests are not an exact match, or the other person is more knowledgeable on a subject, gets too deep and is difficult to keep up. It doesn’t matter, be honest. Ask explanations or to ask to “dumb down the level” a bit, but actively listen and try to understand. Any discussion can provide insights, ideas and solutions to matters that are important to you from a perspective you would never have.

Finally, a few points on presenting. The event included short presentations of R&D proposals and I attended more than 15 myself. Based on my observations of other speakers I made a few notes about presenting for myself and I will share them here with you:
  • Never read from your notes, because the listeners will not be engaged. Know what you want to say
  • The presentation is a discussion where you as a presenter, tell a story to the audience. It’s never a lecture, it’s a story where both speaker and audience should feel involved
  • You can talk about the most complex thing in the world, and you may be the smartest person alive. Still, explain it with simple language, and do not abuse domain jargon because many from the audience may not be familiar
  • Talk as clear as possible and with as good pace as possible, try to not lose your breath and keep the volume and rhythm 
  • Limit as much as possible the “eeem”, “hummm” and phrases such as ‘I mean like’ and “you know?” because they make what you say less interesting and more difficult to follow
That’s all for now folks! As I said it was an interesting event which provided me with insights on different aspects and I was happy to share them with you.

Friday, October 2, 2015

REST client tutorial with Java & Jersey

In my previous post I talked about REST APIs and presented a tutorial on how to create a REST API using Java and Spring. If you missed it, I suggest you take a look at it first here. We used the services of the API using Chrome’s POSTMAN to directly call the exposed URLs. In this post I will create a client to call these services programmatically. To keep things interesting I will use another popular framework for REST web services, Jersey.

The application we built in the previous tutorial is used to manage (geek) diary entries. The application exposed a REST API which can be used to perform CRUD operations on diary entries. Now we will create a client for performing the CRUD operations.

The requirements for replicating and running this tutorial are:


  • JDK 1.7 or higher
  • Maven 
  • Git
  • The 'Geek Diary' services to be deployed and running
  • and use of IDE such as eclipse is also advised
Let's look now at the structure of our REST client tutorial, as is shown in the following figure:




The project is pretty straight forward. In the model package we have the DiaryEntries POJO from the previous tutorial. The util package has the DataTransformationHandler class which contains methods to convert between JSON-Object-Maps, the client package contains methods for calling the CRUD operations via HTTP and we have a demo class to run the application.

The pom file for the Maven project is presented below:
<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.tasosmartidis</groupId>
  <artifactId>rest-client-tutorial</artifactId>
  <version>0.1</version>
  <name>rest-client-tutorial</name>
  
  <dependencies>
    <!-- Jersey -->
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.18.3</version>
    </dependency>   
    <!-- Codehaus Jackson --> 
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency> 
    <!-- JUnit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency>
  </dependencies>
</project>

The POJO for our diary entries is presented in the source code below. We overridden the 'toString()' method to be able to print the entries in the demo program.
package com.tasosmartidis.rest_client_tutorial.model;


public class DiaryEntry {

    private String entryId;
    private String entryTitle;
    private String entryText;
    
    public String getEntryId() {
        return entryId;
    }
    public void setEntryId(String entryId) {
        this.entryId = entryId;
    }
    public String getEntryTitle() {
        return entryTitle;
    }
    public void setEntryTitle(String entryTitle) {
        this.entryTitle = entryTitle;
    }
    public String getEntryText() {
        return entryText;
    }
    public void setEntryText(String entryText) {
        this.entryText = entryText;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((entryId == null) ? 0 : entryId.hashCode());
        result = prime * result
                + ((entryTitle == null) ? 0 : entryTitle.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        DiaryEntry other = (DiaryEntry) obj;
        if (entryId == null) {
            if (other.entryId != null)
                return false;
        } else if (!entryId.equals(other.entryId))
            return false;
        if (entryTitle == null) {
            if (other.entryTitle != null)
                return false;
        } else if (!entryTitle.equals(other.entryTitle))
            return false;
        return true;
    }
    
    @Override
    public String toString(){
        return "[Entry-id: " + entryId + ", entry-title: " + entryTitle + ", entry-text...]";
    }
    
}


Our client application will have to transform data format between JSON to objects and Maps, so we created a few methods for such conversions using the Jackson library.
package com.tasosmartidis.rest_client_tutorial.util;

import java.util.HashMap;
import java.util.Map;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.type.TypeReference;

import com.tasosmartidis.rest_client_tutorial.model.DiaryEntry;

public class DataTransformationHandler {
    
    private ObjectMapper mapper;
    
    public DataTransformationHandler() {
        this.mapper = new ObjectMapper();
    }

    public String convertObjectToJson(Object objectToMap) {
        String mappedJson=null;     
        
        try{
            ObjectWriter objectWriter = mapper.writer().withDefaultPrettyPrinter();
            mappedJson = objectWriter.writeValueAsString(objectToMap);
        }catch(Exception ex) {
            ex.printStackTrace();
        } 
        
        return mappedJson;
    }
    
    public DiaryEntry convertJsonToDiaryEntry(String inputJson) {
        DiaryEntry transformedDiaryEntry = null;
        try{ 
            transformedDiaryEntry = mapper.readValue(inputJson, DiaryEntry.class);
        }catch(Exception ex) {
            ex.printStackTrace();
        } 
        return transformedDiaryEntry;
    }
    
    public Map<String, DiaryEntry> convertJsonToMap(String inputJson) {
        Map<String, DiaryEntry> transformedMap = null;
        try{ 
            transformedMap = mapper.readValue(inputJson, 
                                         new TypeReference<HashMap<String,DiaryEntry>>(){});
        }catch(Exception ex) {
            ex.printStackTrace();
        }
        
        return transformedMap;
    }
}


Now the most important class, the actual REST client. As you can see in the following source code, we have created methods for all the methods of the REST API, in order to create, retrieve, update and delete information from the repository. In each method, a web resource for a specified url is created, the type of the consumed and produced media types are defined along with the HTTP method with the resources to be communicated.
package com.tasosmartidis.rest_client_tutorial.client;

import java.util.Map;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.tasosmartidis.rest_client_tutorial.model.DiaryEntry;
import com.tasosmartidis.rest_client_tutorial.util.DataTransformationHandler;

public class DiaryServiceClient {

    private Client client;
    private WebResource webResource;
    private DataTransformationHandler dataHandler;
    private final String baseUrl = "http://localhost:8080/rest-api-tutorial/service/geek-diaries/entry/";
    
    public DiaryServiceClient() {
        this.client = new Client();
        this.dataHandler = new DataTransformationHandler();
    }
    
    public DiaryEntry createDiaryEntry(String jsonToPost) {
        DiaryEntry createdEntry = null;
        
        try {
            // Create first a Web resource from the client
            webResource = client.resource(baseUrl);  

            // Make the POST request
            ClientResponse response = webResource.accept("application/json")
                                            .type("application/json")
                                            .post(ClientResponse.class, jsonToPost);

            // check response status code
            if (response.getStatus() != 200) {
                throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
            }

            // Map the response of the created DiaryEntry to be returned
            String responseJson = response.getEntity(String.class); 
            createdEntry = dataHandler.convertJsonToDiaryEntry(responseJson);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
        return createdEntry;
    }
    
    public DiaryEntry getDiaryEntry(String entryId) {
        DiaryEntry returnedEntry = null;
        
        try {
            // Create first a Web resource from the client
            webResource = client.resource(baseUrl+entryId);  
            
            // Make the GET request
            ClientResponse response = webResource.accept("application/json")
                                            .type("application/x-www-form-urlencoded")
                                            .get(ClientResponse.class);
           
            // Check response status code
            if (response.getStatus() != 200) { 
                throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
            }
            
            // Map the response to the DiaryEntry to be returned
            String responseJson = response.getEntity(String.class);
            returnedEntry = dataHandler.convertJsonToDiaryEntry(responseJson);
        }catch(Exception ex) {
            ex.printStackTrace();
        }
        
        return returnedEntry;       
    }
    
    public Map<String, DiaryEntry> getDiaryEntries() {
         Map<String, DiaryEntry> resultList = null; 
        
         try {
                Client client = Client.create();
                WebResource webResource = client.resource(baseUrl);  

                // GET method
                ClientResponse response = webResource.accept("application/json")
                        .type("application/x-www-form-urlencoded").get(ClientResponse.class);

                // check response status code
                if (response.getStatus() != 200) {
                    throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
                }

                // display response
                String responseJson = response.getEntity(String.class); 
                resultList = dataHandler.convertJsonToMap(responseJson);
            } catch (Exception e) {
                e.printStackTrace();
            }
         
         return resultList;
    }
    
    public DiaryEntry updateDiaryEntry(String jsonToPut) {
        DiaryEntry updatedEntry = null;
        
        try {
            webResource = client.resource(baseUrl);  

            // Make the PUT call
            ClientResponse response = webResource.accept("application/json")
                                            .type("application/x-www-form-urlencoded")
                                            .type("application/json")
                                            .put(ClientResponse.class, jsonToPut);

            // Check response status code
            if (response.getStatus() != 200) {
                throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
            }

            // Map the response to the DiaryEntry to be returned
            String responseJson = response.getEntity(String.class); 
            updatedEntry = dataHandler.convertJsonToDiaryEntry(responseJson);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
        return updatedEntry;
    }
    
    public String deleteDiaryEntry(String entryId) {
        String deletedEntryId = null;
        
        try {
            webResource = client.resource(baseUrl+entryId);  

            // Make the DELETE request
            ClientResponse response = webResource.accept("application/json")
                                            .type("application/x-www-form-urlencoded")
                                            .delete(ClientResponse.class);

            // Check response status code
            if (response.getStatus() != 200) {
                throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
            }

            // Return the id of the deleted entry
            deletedEntryId = response.getEntity(String.class); 
        } catch (Exception e) {
            e.printStackTrace();
        }
        return deletedEntryId;
    }
}


That was it, our REST client is ready! Let's use all the operations through a simple main class as shown below:
package com.tasosmartidis.rest_client_tutorial.client;

import java.util.Map;

import com.tasosmartidis.rest_client_tutorial.model.DiaryEntry;
import com.tasosmartidis.rest_client_tutorial.util.DataTransformationHandler;

public class RestClientDemo {

    public static void main(String[] args) {
        
        DataTransformationHandler dataHandler = new DataTransformationHandler();
        
        DiaryServiceClient client = new DiaryServiceClient();
        
        // Create a couple of entries to submit
        DiaryEntry entry1 = new DiaryEntry();
        entry1.setEntryTitle("The emergence of the 'API Driven Economy'");
        entry1.setEntryText("The API economy has drastically...");
        
        DiaryEntry entry2 = new DiaryEntry();
        entry2.setEntryTitle("The Internet of Things");
        entry2.setEntryText("The Internet of Things (IoT) is...");
        
        // Convert the POJOs to Json
        String entry1asJson = dataHandler.convertObjectToJson(entry1);
        String entry2asJson = dataHandler.convertObjectToJson(entry2);
        
        // CREATE new diary entries
        System.out.println("*******************************");
        System.out.println("Create entries:");
        System.out.println("*******************************");
        DiaryEntry createdEntry1 = client.createDiaryEntry(entry1asJson);
        DiaryEntry createdEntry2 = client.createDiaryEntry(entry2asJson);
        System.out.println(createdEntry1);
        System.out.println(createdEntry2);
        System.out.println();
        
        // RETRIEVE all of the created entries
        System.out.println("*******************************");
        System.out.println("Retrieve all entries:");
        System.out.println("*******************************");
        printMapEntries(client.getDiaryEntries());
        System.out.println();
        
        // RETRIEVE specific diary entry
        System.out.println("*******************************");
        System.out.println("Retrieve specific entry:");
        System.out.println("*******************************");
        System.out.println(client.getDiaryEntry(createdEntry1.getEntryId()));
        System.out.println();
        
        // UPDATE a diary entry
        // change the POJO to update entry
        createdEntry1.setEntryText("I changed the text!!");
        String updatedEntryAsJson = dataHandler.convertObjectToJson(createdEntry1);
        System.out.println("*******************************");
        System.out.println("Update entry:");
        System.out.println("*******************************");
        System.out.println(client.updateDiaryEntry(updatedEntryAsJson));
        System.out.println();
        
        // DELETE a specific diary entry 
        System.out.println("*******************************");
        System.out.println("Delete specific entry:");
        System.out.println("*******************************");
        System.out.println(client.deleteDiaryEntry(createdEntry2.getEntryId()));   
        System.out.println();
        
        // RETRIEVE all of the created entries (should be missing the deleted one)  
        System.out.println("*******************************");
        System.out.println("Retrieve all entries:");
        System.out.println("*******************************"); 
        printMapEntries(client.getDiaryEntries());
        System.out.println(); 

    }
    
    public static void printMapEntries(Map<String, DiaryEntry> map) {
        
        for (Map.Entry<String, DiaryEntry> entry : map.entrySet()) 
            System.out.println(entry.getKey() + "," + entry.getValue()); 
    }

}


In this demo we create 2 diary entries, retrieve them collectively and independently, update them and delete one of them. Running the program will print the following in the console:


Done! We developed our REST client and it performed as expected when using the CRUD operations. The code is available via github. Till next time!