Edit Page

Lab 8: The Proxy Design Pattern

The goal of this lab is to use the proxy design pattern, a structural design pattern, to solve a real-world problem.

Design patterns are proven solutions to solve recurring design problems to design flexible and reusable object-oriented software; that is, objects that are easier to implement, change, test and reuse. Structural pat­terns deal with the composition of classes or objects while keep­ing them extensible, flex­i­ble and efficient.

The proxy design pattern is one of the twenty-three well-known Gang of Four (GoF) design patterns. It is classified under the category of structural patterns. The proxy design pattern provides a surrogate or placeholder for another object to control access to it. The proxy can provide additional functionality, such as caching, access control, or logging, without modifying the original object. The proxy design pattern can be used to improve the performance, flexibility, and security of object-oriented software.

In this lab, we will protect an OCR service from excessive requests by wrapping it in a rate limiter without changing the OCR service itself. This will prevent the OCR service from being overwhelmed by too many requests, and it will also allow us to restrict access to paid accounts only. Equally important, if we make the OCR service public, spammers could misuse it. We can use the proxy design pattern to prevent spammers from accessing the OCR service and address the following questions:

  • How to protect the OCR service by adding rate limits preventing users from sending too many requests?
  • How to restrict access to an object without modifying it?

Video

Objectives

In this lab you will

  1. understand a real-world scenario and choose when to apply the appropriate design pattern.
  2. design and implement the proxy design pattern.

Requirement and Tools

Getting Started

If your instructor is using GitHub classroom, you will need to accept the assignment using the link below, clone the template repository, and import it as a project into your IDE.

If your instructor is not using GitHub classroom, clone and import the template project at https://github.com/cpit252/lab-08 ↗.

Problem Statement

Lab 8: Proxy Design Pattern for an OCR Service

Optical Character Recognition (OCR) is a technology that allows computers to read text from images. It is used in a variety of applications, such as scanning documents, converting PDFs to text, and recognizing text in images from the internet.

A developer is working on an OCR service that extract text from images. She implemented the OCR service using Tesseract, an open-source optical character recognition (OCR) engine. She released the service to the public and it was well-received, but spammers and abusers proliferated. To address this, she decided to implement a rate limiter that would restrict non-paid users to a fixed number of requests per day. She believed that it was imperative to implement this new rate limiting feature using the proxy design pattern.

Using the proxy design pattern is a good way to protect this service with a rate limiter. A proxy allows her to implement rate limiting without changing the underlying OCR service, making it easier to change or remove rate limiting and monetize the service.

The proxy design pattern embodies the object-oriented principle of “programming to an interface, not an implementation.” This means that you should design your objects to interact with each other through interfaces, rather than concrete implementations.

She started out creating an interface called OCRService.

Lab 8: Proxy Design Pattern for an OCR Service UML diagram

OCRService.java

1
2
3
public interface OCRService {
    String recognizeText(String imagePath, String language) throws Exception;
}

Next, she created the service that performs OCR on images using Tesseract.

RealOCRService.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import net.sourceforge.tess4j.Tesseract;
import java.io.File;

public class RealOCRService implements OCRService {
    private Tesseract tesseract;
    public RealOCRService(String dataPath){
        this.tesseract = new Tesseract();
        tesseract.setDatapath(dataPath);
    }
    /**
     * performs OCR on the given image for the given language
     * @param imagePath the path to the image that contains text
     * @param language the first three letters of the target language. Multiple languages can
     *                 be combined with the plus sign (e.g., eng+ara).
     * @return the text that was detected in the image
     */
    @Override
    public String recognizeText(String imagePath, String language) throws Exception {
        if(imagePath == null || language == null) {
            System.err.println("Image path and the target language are required.");
            return null;
        }
        File imageFile = new File(imagePath);
        tesseract.setLanguage(language);
        return tesseract.doOCR(imageFile);
    }
}

OCRServiceProxy.java

1
2
3
public class OCRServiceProxy {

}

Question:

Complete the implementation of the proxy design pattern to protect the RealOCRService by implementing a rate limiter in the OCRServiceProxy. This proxy should restrict non-paid users to a fixed number of requests.

Deliverables and Submission

Extra Task [Optional]

If you are done with this activity, you may enable a continuos integration tool such as CircleCI ↗ to automatically run your JUnit test upon code changes. You may also add more unit tests to increase code coverage. Please embed the badge that shows the status of your build and test (passing/failing) as well as the coverage percentage into your README file (e.g., passing status image and failing status image). Please be sure to fork the repository or push to a remote repository under your own account, so you can enable the integration of CI tools in your own account.

You may refer to the lecture notes from the prerequisite course CPIT-251 on Continuous Integration (CI) and adding a code coverage badge.