Upload and Download files to S3 using maven.

Throughout the years I’ve seen many teams using maven in many different ways. Maven can be used for many ci/cd tasks instead of using extra pipeline code or it can be used to prepare the development environment before running some tests.
Generally it is convenient tool, widely used among java teams and will continue so since there is a huge ecosystem around it.

The CloudStorage Maven plugin helps you with using various cloud buckets as a private maven repository. Recently CloudStorageMaven for s3 got a huge upgrade, and you can use it in order to download or upload files from s3, by using it as a plugin.

The plugin assumes that your environment is configured properly to access the s3 resources needed.
This can be achieved individually through aws configure

aws configure

Other ways are through environmental variables or by using the appropriate iam role.

Supposing you want to download some certain files from a path in s3.

<build>
        <plugins>
            <plugin>
                <groupId>com.gkatzioura.maven.cloud</groupId>
                <artifactId>s3-storage-wagon</artifactId>
                <version>1.6</version>
                <executions>
                    <execution>
                        <id>download-one</id>
                        <phase>package</phase>
                        <goals>
                            <goal>s3-download</goal>
                        </goals>
                        <configuration>
                            <bucket>your-bucket</bucket>
                            <downloadPath>/local/download/path</downloadPath>
                            <keys>1.txt,2.txt,directory/3.txt</keys>
                        </configuration>
                    </execution>
                <executions>
            <plugin>
        <plugins>
</build>

The files 1.txt,2.txt,directory/3.txt once the execution is finished shall reside in the local directory specified
(/local/download/path).
Be aware that the file discovery on s3 is done with prefix, thus if you have file 1.txt and 1.txt.jpg both files shall be downloaded.

You can also download only one file to one file that you specified locally, as long as it is one to one.

                    <execution>
                        <id>download-prefix</id>
                        <phase>package</phase>
                        <goals>
                            <goal>s3-download</goal>
                        </goals>
                        <configuration>
                            <bucket>your-bucket</bucket>
                            <downloadPath>/path/to/local/your-file.txt</downloadPath>
                            <keys>a-key-to-download.txt</keys>
                        </configuration>
                    </execution>

Apparently files with a prefix that contain directories (they are fakes ones on s3) will downloaded to the directory specified in the form of directories and sub directories

                    <execution>
                        <id>download-prefix</id>
                        <phase>package</phase>
                        <goals>
                            <goal>s3-download</goal>
                        </goals>
                        <configuration>
                            <bucket>your-bucket</bucket>
                            <downloadPath>/path/to/local/</downloadPath>
                            <keys>s3-prefix</keys>
                        </configuration>
                    </execution>

The next part is about uploading files to s3.

Uploading one file

                    <execution>
                        <id>upload-one</id>
                        <phase>package</phase>
                        <goals>
                            <goal>s3-upload</goal>
                        </goals>
                        <configuration>
                            <bucket>your-bucket</bucket>
                            <path>/path/to/local/your-file.txt</path>
                            <key>key-to-download.txt</key>
                        </configuration>
                    </execution>

Upload a directory

                    <execution>
                        <id>upload-one</id>
                        <phase>package</phase>
                        <goals>
                            <goal>s3-upload</goal>
                        </goals>
                        <configuration>
                            <bucket>your-bucket</bucket>
                            <path>/path/to/local/directory</path>
                            <key>prefix</key>
                        </configuration>
                    </execution>

Upload to the root of bucket.

                    <execution>
                        <id>upload-multiples-files-no-key</id>
                        <phase>package</phase>
                        <goals>
                            <goal>s3-upload</goal>
                        </goals>
                        <configuration>
                            <bucket>your-bucket</bucket>
                            <path>/path/to/local/directory</path>
                        </configuration>
                    </execution>

That’s it! Since it is an open source project you can contribute or issue pull requests at github.

Behavioural Design Patterns: Template method

Previously we used the strategy pattern to in order to solve the problem of choosing various speeding algorithms based on the road type. The next behavioural design pattern we are going to use is the template method.
By using the template method we define the skeleton of the algorithm and the implementation of certain steps is done by subclasses.

Thus we have methods with concrete implementations, and methods without any implementation. Those methods will be implemented based on the application logic needed to be achieved.

Imagine the case of a coffee machine. There are many types of coffees and different ways to implement them, however some steps are common and some steps although they vary they also need to be implemented. Processing the beans, boiling, processing the milk, they are all actions that differ based on the type of coffee. Placing to a cup and service however are actions that do no differentiate.

package com.gkatzioura.design.behavioural.template;

public abstract class CoffeeMachineTemplate {

    protected abstract void processBeans();

    protected abstract void processMilk();

    protected abstract void boil();

    public void pourToCup() {
        /**
         * pour to various cups based on the size
         */
    }

    public void serve() {
        processBeans();
        boil();
        processMilk();
        pourToCup();
    }

}

Then we shall add an implementation for the espresso. So here’s our espresso machine.

package com.gkatzioura.design.behavioural.template;

public class EspressoMachine extends CoffeeMachineTemplate {

    @Override
    protected void processBeans() {
        /**
         * Gring the beans
         */
    }

    @Override
    protected void processMilk() {
        /**
         * Use milk to create leaf art
         */
    }

    @Override
    protected void boil() {
        /**
         * Mix water and beans
         */
    }
}

As you see we can create various coffee machine no matter how different some steps might be.
You can find the sourcecode on github.

Behavioural Design Patterns: Strategy

Previously we used the state in order to add some functionality to an application based on the user state. Our next behavioural design pattern is Strategy.
The strategy pattern enables us to select an algorithm at runtime. Based on the instructions our program will pick the most suitable algorithm instead of implementing an algorithm directly. This makes our codebase more flexible and keep it clean from any extra logic.

Our example shall evolve around vehicles and the speeding that is allowed based on the type of road. For example if a vehicle is on a four lane road the speed would be way different than being on an urban area road.
So we are actually going to implement the strategy patterns with regards to speeding.

We will start with the speeding interface.

package com.gkatzioura.design.behavioural.strategy;

public interface Speeding {

    Double adjustSpeed(Double currentSpeed);

}

Then we shall create some implementations based on the road type.
The four lane speeding implementation adjusts the speeding when driving on a four lane.

package com.gkatzioura.design.behavioural.strategy;

public class FourLaneSpeeding implements Speeding {

    private static final Double upperLimit = 50d;

    @Override
    public Double adjustSpeed(Double currentSpeed) {
        if(currentSpeed>upperLimit) {
            currentSpeed = upperLimit;
        }

        System.out.println("Speed adjusted at "+currentSpeed);

        return currentSpeed;
    }

}

The urban area speeding implementation adjusts the speeding when driving on a rural road.

package com.gkatzioura.design.behavioural.strategy;

public class UrbanAreaSpeeding implements Speeding {

    private static final Double upperLimit = 30d;

    @Override
    public Double adjustSpeed(Double currentSpeed) {
        if(currentSpeed>upperLimit) {
            currentSpeed = upperLimit;
        }

        System.out.println("Speed adjusted at "+currentSpeed);

        return currentSpeed;
    }

}

And then we shall create the vehicle class.

package com.gkatzioura.design.behavioural.strategy;

public class Vehicle {

    private Speeding speeding;
    private Double currentSpeed;

    public void drive() {

        speeding.adjustSpeed(currentSpeed);

        /**
         * Driving related actions.
         */
    }

    public void setSpeeding(Speeding speeding) {
        this.speeding = speeding;
    }

    public void setCurrentSpeed(Double currentSpeed) {
        this.currentSpeed = currentSpeed;
    }
}

As you can see the vehicle shall change its speeding strategy based on the road driving.
Let’s put them all together.

package com.gkatzioura.design.behavioural.strategy;

public class Strategy {

    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle();

        vehicle.setCurrentSpeed(70d);
        
        vehicle.drive();
        
        /**
         * Changed route
         */
        
        vehicle.setSpeeding(new FourLaneSpeeding());

        vehicle.drive();

        /**
         * Changed route
         */
        
        vehicle.setSpeeding(new UrbanAreaSpeeding());

        vehicle.drive();
    }
}

That’s all for now! You can find the sourcecode on github.

Kubernetes and Secrets

This is going to be a small post since it has to deal with kubernetes and secrets. Yet it is a very useful once since adding secrets is so common yet so easy to forget (guilty as charged).

So we will cover username and password, key/values, file uploading, secrets.

Upload username and password using command line.

kubectl create secret generic accountpassword --from-literal=username=yourusername --from-literal=password=yourpassword

Upload just a key

kubectl create secret generic application-key --from-literal=key=yourusername

Upload username and password through files

printf "yourusername" > username.txt
printf "yourpassword" > password.txt
kubectl create secret generic accountpassword --from-file=./username.txt --from-file=./password.txt

Then let’s upload a secret. Be aware that this secret can be used with your secret rules.

kubectl create secret tls your-server-tls --key ./privkey.pem --cert ./fullchain.pem

Another step is to upload a file. This file can then be used by being mounted on your container.

kubectl create secret generic secretfile --from-file=key.json=./secret_json.yaml

Then you can mount it to the pod

    spec:
      volumes:
      - name: secret-json
        secret:
          secretName: secretfile
      containers:
      - name: containername
        volumeMounts:
        - name: secret-json
          mountPath: /var/secrets/json

That’s all! The full docs can be found here.

Behavioural Design patterns: State

The state pattern deals with altering an object’s behaviour when its state changes.

Imagine the case of a class responsible for generating user interface based on the state. You got anonymous, logged-in and admin users.

We shall create an interface called GreetingState which defines the action of drawing a html text with a welcome message to the user. There is going to be a different implementation according to the states that we have.

package com.gkatzioura.design.behavioural.state;

public interface GreetingState {

    String create();

}

We shall implement the GreetingState for the anonymous user.

package com.gkatzioura.design.behavioural.state;

public class AnonymousGreetingState implements GreetingState {

    private static final String FOOTER_MESSAGE = "<p><Hello anonymous user!</p>";

    @Override
    public String create() {
        return FOOTER_MESSAGE;
    }

}

Then we shall implement the GreetingState for the logged in user. This one would create a personalised message.

package com.gkatzioura.design.behavioural.state;

public class LoggedInGreetingState implements GreetingState {

    private static final String FOOTER_MESSAGE = "<p><Hello %s!</p>";

    private final String username;

    public LoggedInGreetingState(final String username) {
        this.username = username;
    }

    @Override
    public String create() {
        return String.format(FOOTER_MESSAGE,username);
    }

}

And at last the admin Footer.

package com.gkatzioura.design.behavioural.state;

import java.util.Date;

public class AdminGreetingState implements GreetingState {

    private static final String FOOTER_MESSAGE = "<p><Hello %s, last login was at %s</p>";

    private final String username;
    private final Date lastLogin;

    public AdminGreetingState(final String username, Date lastLogin) {
        this.username = username;
        this.lastLogin = lastLogin;
    }


    @Override
    public String create() {
        return String.format(FOOTER_MESSAGE,username,lastLogin);
    }

}

The we shall create the stateui context.

package com.gkatzioura.design.behavioural.state;

import java.io.PrintWriter;

public class StateUIContext {

    private GreetingState greetingState;

    public void setGreetingState(GreetingState greetingState) {
        this.greetingState = greetingState;
    }

    public void create(PrintWriter printWriter) {
        printWriter.write(greetingState.create());
    }
}

Let’s put them all together.

package com.gkatzioura.design.behavioural.state;

import java.io.PrintWriter;
import java.util.Date;

public class StateMain {

    public static void main(String[] args) {

        StateUIContext stateUIContext = new StateUIContext();

        try(PrintWriter printWriter = new PrintWriter(System.out)) {
            stateUIContext.setGreetingState(new AnonymousGreetingState());
            stateUIContext.create(printWriter);
            printWriter.write("\n");
            stateUIContext.setGreetingState(new LoggedInGreetingState("someone"));
            stateUIContext.create(printWriter);
            printWriter.write("\n");
            stateUIContext.setGreetingState(new AdminGreetingState("admin",new Date()));
            stateUIContext.create(printWriter);
            printWriter.write("\n");
        }
    }
}

You can find the sourcecode on github.

Behavioural Design patterns: Observer

Observer is one of the most popular design patterns. It has been used a lot on many software use cases and thus many languages out there provide it as a part of their standard library.

By using the observer pattern we can tackle the following challenges.

  • Dependency with objects defined in a way that avoids tight coupling
  • Changes on an object changes its dependent objects
  • An object can notify all of its dependent objects

Imagine the scenario of a device with multiple sensors. Some parts of the code will need to get notified when new sensor data arrive and thus act accordingly. We will start by a simple class which represents the json data.

package com.gkatzioura.design.behavioural.observer;

public class SensorData {

    private final String sensor;
    private final Double measure;

    public SensorData(String sensor, Double measure) {
        this.sensor = sensor;
        this.measure = measure;
    }

    public String getSensor() {
        return sensor;
    }

    public Double getMeasure() {
        return measure;
    }
}

The we shall create the observer interface. Every class that implements the observer interface shall be notified once a new object is created.

package com.gkatzioura.design.behavioural.observer;

public interface Observer {

    void update(SensorData sensorData);

}

Next step is to create the observable interface. The observable interface will have methods in order to register the observers that need to get notified.

package com.gkatzioura.design.behavioural.observer;

public interface Observable {

    void register(Observer observer);

    void unregister(Observer observer);

    void updateObservers();

}

Now let us put some implementations.
The sensor listener will receive data from the sensors and notify the observers about the presence of data.

package com.gkatzioura.design.behavioural.observer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class SensorReceiver implements Observable {

    private List data = new ArrayList();
    private List observers = new ArrayList();

    @Override
    public void register(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void unregister(Observer observer) {
        observers.remove(observer);
    }

    public void addData(SensorData sensorData) {
        data.add(sensorData);
    }

    @Override
    public void updateObservers() {

        /**
         * The sensor receiver has retrieved some sensor data and thus it will notify the observer
         * on the data it accumulated.
         */

        Iterator iterator = data.iterator();

        while (iterator.hasNext()) {

            SensorData sensorData = iterator.next();

            for(Observer observer:observers) {
                observer.update(sensorData);
            }

            iterator.remove();
        }
    }

}

The we will create an observer which shall log the sensor data received to database, it might be an influxdb or an elastic search you name it.

package com.gkatzioura.design.behavioural.observer;

public class SensorLogger implements Observer {

    @Override
    public void update(SensorData sensorData) {

        /**
         * Persist data to the database
         */

        System.out.println(String.format("Received sensor data %s: %f",sensorData.getSensor(),sensorData.getMeasure()));
    }

}

Let’s put the all together.

package com.gkatzioura.design.behavioural.observer;

public class SensorMain {

    public static void main(String[] args) {

        SensorReceiver sensorReceiver = new SensorReceiver();
        SensorLogger sensorLogger = new SensorLogger();
        sensorReceiver.register(sensorLogger);
        sensorReceiver.addData(new SensorData("temperature",1.2d));
        sensorReceiver.updateObservers();
    }
}

You can find the source code on github.

Behavioural Design patterns: Memento

The memento pattern is all about state. You use it when you want to restore the object to its previous state.
You have an object, you apply some actions and you are able to revert those actions and get the object in the various states it has been before.

Most of us implement various algorithms and sometimes we do need to evaluate em. Imagine having a program that evaluates trade decisions and you want to go to a previous state and check what would happen to the account balance if you change the formula, and then evaluate the account balance for each step.

The steps of the algorithm and what you should change will definitely vary. The memento pattern will assist us to our mission and help us do some fast in memory evaluation.

We will have a Memento object that contains the account balance.
Memento will represent the balance on different phases.

package com.gkatzioura.design.behavioural.memento;

public class Memento {

    private Double balance;

    public Memento(Double balance) {
        this.balance = balance;
    }

    public Double getBalance() {
        return balance;
    }
}

Then we will create the originator object. The originator will contain the current state. It can pass it back as a memento when we need to store it. Also we can use a memento object to it restore a certain state.

package com.gkatzioura.design.behavioural.memento;

public class Originator {

    private Double balance;

    public void setBalance(Double balance) {
        this.balance = balance;
    }

    public Double getBalance() {
        return balance;
    }

    public Memento saveToMemento() {
        return new Memento(balance);
    }

    public void restoreToState(Memento memento) {
        balance =  memento.getBalance();
    }
}

The last step is the CareTaker object, this will contain the history of our balance. The caretaker will fetch the object state during their various phases.

package com.gkatzioura.design.behavioural.memento;

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

public class CareTaker {

    private List mementoList = new ArrayList();

    public void add(Memento state){
        mementoList.add(state);
    }

    public Memento get(int index){
        return mementoList.get(index);
    }

}

So let’s put them all together.

package com.gkatzioura.design.behavioural.memento;

public class MementoMain {

    public static void main(String[] args) {

        Double balance = 20.1d;

        Originator originator = new Originator();
        originator.setBalance(balance);

        CareTaker careTaker = new CareTaker();

        careTaker.add(originator.saveToMemento());

        /**
         * Do a transaction
         */

        originator.setBalance(balance-2);
        careTaker.add(originator.saveToMemento());

        /**
         * Do a transaction
         */

        originator.setBalance(balance+4);
        careTaker.add(originator.saveToMemento());

        System.out.println(careTaker.get(0).getBalance());
        System.out.println(careTaker.get(1).getBalance());
        System.out.println(careTaker.get(2).getBalance());
    }
}

You can find the source code on github.

Behavioural Design Patterns: Mediator

Previously we had a look at the iterator pattern.

The mediator pattern is way different on what it tries to achieve. It is one of the behavioural patterns and its purpose is to alter the way objects communicate with each other. Instead of the objects communicating with each other directly the mediator will handle the objects interaction.

For example imagine the scenario of a financial exchange. You do want to trade and buy but you don’t buy directly from the one that makes the offer.
Instead the exchange is in the middle, in order for you to make the transaction.

People would like to sell and buy. This shall be facilitated by the exchange.
You got the order object.

package com.gkatzioura.design.behavioural.mediator;

public class Order {

    private String stock;
    private Integer quantity;
    private Double price;

    public String getStock() {
        return stock;
    }

    public void setStock(String stock) {
        this.stock = stock;
    }

    public Integer getQuantity() {
        return quantity;
    }

    public void setQuantity(Integer quantity) {
        this.quantity = quantity;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

}

The next object would be the financial entity that sells the stocks.

package com.gkatzioura.design.behavioural.mediator;

public class FinancialEntity {

    public boolean sell(Order order) {

        /**
         * Supposing the sale was successful return true
         */
        return true;
    }

}

Then we create the exchange object. We won’t get further into commissions but imagine that things can be way more complex. The exchange is actually our mediator.

package com.gkatzioura.design.behavioural.mediator;

public class Exchange {

    private FinancialEntity financialEntity;

    public Exchange(FinancialEntity financialEntity) {
        this.financialEntity = financialEntity;
    }

    public void serve(Order order) {

        /**
         * Choose the financial entity suitable for the order
         */
        financialEntity.sell(order);
    }

}

And the last step is creating the trader object.

package com.gkatzioura.design.behavioural.mediator;

public class Trader {

    private Exchange exchange;

    public Trader(Exchange exchange) {
        this.exchange = exchange;
    }

    public void buy(String stock,Integer quantity,Double price) {
        Order order = new Order();
        order.setStock(stock);
        order.setQuantity(quantity);
        order.setPrice(price);
        exchange.serve(order);
    }

}

As you can see the trader object is not interacting directly with the financial entity that provides the stocks.

Let’s put them all together in a main class.

package com.gkatzioura.design.behavioural.mediator;

public class Mediator {

    public static void main(String[] args) {

        final FinancialEntity financialEntity = new FinancialEntity();
        final Exchange exchange = new Exchange(financialEntity);
        Trader trader = new Trader(exchange);
        trader.buy("stock_a",2,32.2d);
    }
}

That’s it, you just used the mediator pattern for an exchange application! You can also find the source code on github.

Fully working prototypes with Spring Boot and H2

We do use a lot of h2 with spring especially for unit tests. However instead of unit tests we might want to have a fully functional prototype with data to display.
H2 is the perfect candidate for that, it works great with spring, it has good syntax compatibility with most databases out there and it also provides you with a ui to check your data.

Imagine the scenario of an interview assignment. You want your example to work out of the box with as minimum as possible configuration for the reviewer.
The plan is to have an application up and running with some data.
Before accessing the application we might as well want to add some data to it. Then we need to have a proper way to display the data added without adding extra code.

The first step is to go to the spring initializr and add the Web and H2 dependencies. Also we shall add the jdbc property.

The end result will give a build.gradle file like this.

buildscript {
	ext {
		springBootVersion = '2.0.6.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.gkatzioura.springbooth2'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
	mavenCentral()
}

dependencies {
	implementation('org.springframework.boot:spring-boot-starter-jdbc')
	implementation('org.springframework.boot:spring-boot-starter-web')
	runtimeOnly('com.h2database:h2')
	testImplementation('org.springframework.boot:spring-boot-starter-test')
}

Since we added the jdbc property we can have some schema scripts executed once the application is started.
Thus we need to create a schema.sql file containing the sql statements which create the schema.

CREATE TABLE application_user (ID INT, USER_NAME VARCHAR(50), PASSWORD VARCHAR(255));
INSERT INTO application_user (ID,USER_NAME, PASSWORD) values (1,'test','password-hash');

The next step is to enable the h2 console. We will go with the yaml approach however you can do it either using a properties file or environmental variables.

spring:
  h2:
    console:
      enabled: true

Now once we get our spring application running we can navigate at the http://localhost:8080/h2-console endpoint.
We shall be presented with the default credentials needed

Once we have logged in, we can query for the user we had inserted on our startup sql script.

Screen Shot 2018-11-05 at 07.36.20.png

That’s it! This can make wonders for prototypes, interview assignments and blog posts like this!

Behavioural Design Patterns: Iterator

The iterator pattern is one of the most used patterns from the behavioural ones. Most of the times you use it without even noticing it. Supposing you have a container with elements and you want to traverse them. Iterating the elements might differ based on the container, retrieval method etc. By using the iterator pattern we can decouple the algorithms used by the containers, and the retrieval methods and abstract the iteration of the elements contained.

For example when it comes to retrieving paged data from a rest endpoint the iterator can help you to abstract it. Therefore you won’t expose the user with any information on how you retrieve the next batch of data.

I will make a new iterator interface similar the one provided by the java language.

package com.gkatzioura.design.behavioural.iterator;

public interface Iterator<T> {

    boolean hasNext();
    
    T next();
    
}

We will use the github jobs api since it is open to issue rest queries and search for jobs.
The first page is page zero.

https://jobs.github.com/positions.json?page=0.

We shall create a simple object which would contain the id, title and company information.

package com.gkatzioura.design.behavioural.iterator;

import java.util.UUID;

public class GitHubJob {

    private final UUID id;
    private final String company;
    private final String title;

    public GitHubJob(UUID id, String company, String title) {
        this.id = id;
        this.company = company;
        this.title = title;
    }

    public UUID getId() {
        return id;
    }

    public String getCompany() {
        return company;
    }

    public String getTitle() {
        return title;
    }
}

Our first step would be to create a repository witch shall fetch the data of the page specified.

package com.gkatzioura.design.behavioural.iterator;

import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;

public class GitHubJobsRepository {

    public static final String GITHUB_JOB_API = "https://jobs.github.com/positions.json?page=";

    public List<GitHubJob> fetch(int page) throws Exception {

        List<GitHubJob> gitHubJobs = new ArrayList<>();

        URL url = new URL(GITHUB_JOB_API+page);
        HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
        String response = IOUtils.toString(httpConnection.getInputStream(), Charset.defaultCharset());
        JSONArray jsonArray = new JSONArray(response);

        for(int i=0;i<jsonArray.length();i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            GitHubJob gitHubJob = new GitHubJob(
                    UUID.fromString(jsonObject.getString("id")),
                    jsonObject.getString("company"),
                    jsonObject.getString("title"));
            gitHubJobs.add(gitHubJob);
        }

        return gitHubJobs;
    }

}

What’s great with this api is that if you ask for a page that does not exists you get an empty json object, thus asking for a non existing page won’t give us an exception like 404, therefore no need for error handling for this case.

Now the interesting part is the iterator.

package com.gkatzioura.design.behavioural.iterator;

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

public class GitHubIterator implements Iterator<GitHubJob> {

    private List<GitHubJob> currentJobsPage = new ArrayList<>();
    private int page = 0;

    private final GitHubJobsRepository gitHubJobsRepository;

    public GitHubIterator(GitHubJobsRepository gitHubJobsRepository) {
        this.gitHubJobsRepository = gitHubJobsRepository;
    }

    @Override
    public boolean hasNext() {
        fetchPageIfNeeded();
        return currentJobsPage.size()>0;
    }

    @Override
    public GitHubJob next() {
        fetchPageIfNeeded();

        if(currentJobsPage.size()==0) {
            return null;
        }

        return currentJobsPage.remove(0);
    }

    private void fetchPageIfNeeded() {
        if(page == -1) {
            return;
        }

        if(currentJobsPage==null||currentJobsPage.size()==0) {
            try {
                currentJobsPage = gitHubJobsRepository.fetch(page);
                if(currentJobsPage.size()==0) {
                    page = -1;
                } else {
                    page++;
                }
            } catch (Exception e) {
                throw new RuntimeException();
            }
        }
    }
}

The iterator shall contain a page request from github. For each element requested one item shall be removed from the page. Once the page gets empty a new page shall be requested.

Whether the user asks for another element or if another element exists the code shall check if the current page is empty and if yes it will request for the next page. If we got an empty page this mean that there should not be any extra request to the iterator.

The next step would be to add a method to the repository which shall give back the github iterator.

public class GitHubJobsRepository {

...

    public Iterator<GitHubJob> iterator() {
        return new GitHubIterator(this);
    }

...
}

So let us sum up and iterate over all the entries.

package com.gkatzioura.design.behavioural.iterator;

public class IteratorExample {

    public static void main(String[] args) throws Exception {
        GitHubJobsRepository gitHubJobsRepository = new GitHubJobsRepository();

        Iterator<GitHubJob> gitHubJobIterator = gitHubJobsRepository.iterator();

        while (gitHubJobIterator.hasNext()) {
            GitHubJob gitHubJob = gitHubJobIterator.next();
            System.out.println(String.format(" id: %s title: %s company: %s",gitHubJob.getId(),gitHubJob.getTitle(),gitHubJob.getCompany()));
        }
    }

}

You can find the source code on github.

It is also worth referencing patterns we saw previously such as the interpreter, chain of responsibility and the command pattern.