Skip to content

Commit

Permalink
refactor: Resolved issue #2979 Refactor Front Controller (#2986)
Browse files Browse the repository at this point in the history
Co-authored-by: Mayankchoudhary294 <mayankchoudhary4302@example.com>
  • Loading branch information
Mayankchoudhary294 and Mayankchoudhary294 committed Jun 6, 2024
1 parent f0611bc commit f42e60c
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 39 deletions.
54 changes: 38 additions & 16 deletions front-controller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Wikipedia says

The Front Controller design pattern is a pattern that provides a centralized entry point for handling all requests in a web application. It ensures that request handling is managed consistently and efficiently across an application.

In the provided code, we can see an example of the Front Controller pattern in the `App` and `FrontController` classes.
In the provided code, we can see an example of the Front Controller pattern in the `App`, `FrontController` and `Dispatcher` classes.

The `App` class is the entry point of the application. It creates an instance of `FrontController` and uses it to handle various requests.

Expand All @@ -52,33 +52,55 @@ public class App {
}
```

The `FrontController` class is the front controller in this example. It handles all requests and routes them to the appropriate handlers.
The `FrontController` class is the front controller in this example. It handles all requests and delegates them to the `Dispatcher`.

```java
public class FrontController {

public void handleRequest(String request) {
Command command;

switch (request) {
case "Archer":
command = new ArcherCommand();
break;
case "Catapult":
command = new CatapultCommand();
break;
default:
command = new UnknownCommand();
private final Dispatcher dispatcher;

public FrontController() {
this.dispatcher = new Dispatcher();
}

public void handleRequest(String request) {
dispatcher.dispatch(request);
}
}
```

The `Dispatcher` class is responsible for handling the dispatching of requests to the appropriate command. It retrieves the corresponding command based on the request and invokes the command's process method to handle the business logic.

```java
public class Dispatcher {

public void dispatch(String request) {
var command = getCommand(request);
command.process();
}

Command getCommand(String request) {
var commandClass = getCommandClass(request);
try {
return (Command) commandClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new ApplicationException(e);
}
}

static Class<?> getCommandClass(String request) {
try {
return Class.forName("com.iluwatar.front.controller." + request + "Command");
} catch (ClassNotFoundException e) {
return UnknownCommand.class;
}
}
}
```

In this example, when a request is received, the `FrontController` creates a command object based on the request and calls its `process` method. The command object is responsible for handling the request and rendering the appropriate view.
In this example, when a request is received, the `FrontController` delegates the request to the `Dispatcher`, which creates a command object based on the request and calls its `process` method. The command object is responsible for handling the request and rendering the appropriate view.

This is a basic example of the Front Controller pattern, where all requests are handled by a single controller, ensuring consistent and efficient request handling.
This is a basic example of the Front Controller pattern, where all requests are handled by a single controller and dispatcher, ensuring consistent and efficient request handling.

## Class diagram

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
package com.iluwatar.front.controller;

/**
* The Front Controller is a presentation tier pattern. Essentially it defines a controller that
* The Front Controller is a presentation tier pattern. Essentially, it defines a controller that
* handles all requests for a website.
*
* <p>The Front Controller pattern consolidates request handling through a single handler object (
* {@link FrontController}). This object can carry out the common the behavior such as
* authorization, request logging and routing requests to corresponding views.
* {@link FrontController}). This object can carry out common behavior such as authorization,
* request logging and routing requests to corresponding views.
*
* <p>Typically the requests are mapped to command objects ({@link Command}) which then display the
* <p>Typically, the requests are mapped to command objects ({@link Command}) which then display the
* correct view ({@link View}).
*
* <p>In this example we have implemented two views: {@link ArcherView} and {@link CatapultView}.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
*
* The MIT License
* Copyright © 2014-2022 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.front.controller;

/**
* The Dispatcher class is responsible for handling the dispatching of requests to the appropriate
* command. It retrieves the corresponding command based on the request and invokes the command's
* process method to handle the business logic.
*/
public class Dispatcher {

/**
* Dispatches the request to the appropriate command.
*
* @param request the request to be handled
*/
public void dispatch(String request) {
var command = getCommand(request);
command.process();
}

/**
* Retrieves the appropriate command instance for the given request.
*
* @param request the request to be handled
* @return the command instance corresponding to the request
*/
Command getCommand(String request) {
var commandClass = getCommandClass(request);
try {
return (Command) commandClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new ApplicationException(e);
}
}

/**
* Retrieves the Class object for the command corresponding to the given request.
*
* @param request the request to be handled
* @return the Class object of the command corresponding to the request
*/
static Class<?> getCommandClass(String request) {
try {
return Class.forName("com.iluwatar.front.controller." + request + "Command");
} catch (ClassNotFoundException e) {
return UnknownCommand.class;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,19 @@
package com.iluwatar.front.controller;

/**
* FrontController is the handler class that takes in all the requests and renders the correct
* response.
* The FrontController is responsible for handling all incoming requests. It delegates
* the processing of requests to the Dispatcher, which then determines the appropriate
* command and view to render the correct response.
*/
public class FrontController {

public void handleRequest(String request) {
var command = getCommand(request);
command.process();
}
private final Dispatcher dispatcher;

private Command getCommand(String request) {
var commandClass = getCommandClass(request);
try {
return (Command) commandClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new ApplicationException(e);
}
public FrontController() {
this.dispatcher = new Dispatcher();
}

private static Class<?> getCommandClass(String request) {
try {
return Class.forName("com.iluwatar.front.controller." + request + "Command");
} catch (ClassNotFoundException e) {
return UnknownCommand.class;
}
public void handleRequest(String request) {
dispatcher.dispatch(request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
*
* The MIT License
* Copyright © 2014-2022 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.front.controller;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class DispatcherTest {

private Dispatcher dispatcher;

@BeforeEach
public void setUp() {
dispatcher = new Dispatcher();
}

@Test
void testDispatchKnownCommand() {
Command mockCommand = mock(ArcherCommand.class);
dispatcher = spy(dispatcher);
doReturn(mockCommand).when(dispatcher).getCommand("Archer");

dispatcher.dispatch("Archer");

verify(mockCommand, times(1)).process();
}

@Test
void testDispatchUnknownCommand() {
Command mockCommand = mock(UnknownCommand.class);
dispatcher = spy(dispatcher);
doReturn(mockCommand).when(dispatcher).getCommand("Unknown");

dispatcher.dispatch("Unknown");

verify(mockCommand, times(1)).process();
}

@Test
void testGetCommandKnown() {
Command command = dispatcher.getCommand("Archer");
assertNotNull(command);
assertTrue(command instanceof ArcherCommand);
}

@Test
void testGetCommandUnknown() {
Command command = dispatcher.getCommand("Unknown");
assertNotNull(command);
assertTrue(command instanceof UnknownCommand);
}

@Test
void testGetCommandClassKnown() {
Class<?> commandClass = Dispatcher.getCommandClass("Archer");
assertNotNull(commandClass);
assertEquals(ArcherCommand.class, commandClass);
}

@Test
void testGetCommandClassUnknown() {
Class<?> commandClass = Dispatcher.getCommandClass("Unknown");
assertNotNull(commandClass);
assertEquals(UnknownCommand.class, commandClass);
}
}

0 comments on commit f42e60c

Please sign in to comment.