Commit 472cb53f authored by abdullh.alsoleman's avatar abdullh.alsoleman

initial

parent 7f86961f
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="httpclient" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="httpclient" options="--add-modules java.net.http" />
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17 (2)" project-jdk-type="JavaSDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<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>org.example</groupId>
<artifactId>httpclient</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<logback.version>1.2.3</logback.version>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class Aggregator {
private WebClient webClient;
public Aggregator() {
this.webClient = new WebClient();
}
/* Send tasks to a list of workers and return results */
public List<String> sendTasksToWorkers(List<String> workersAddresses, List<String> tasks) {
List<String> results = new ArrayList<>();
for (String address:workersAddresses) {
results.add(sendTaskToWorker(address, tasks));
}
return results;
}
/* Send tasks to a specific worker with default headers and return result */
private String sendTaskToWorker(String workerAddress, List<String> tasks) {
String url = workerAddress + "/task";
List<CompletableFuture<String>> future = new ArrayList<>();
for (String task : tasks) {
byte[] requestPayload = String.join(",", task).getBytes();
future.add(webClient.sendTask(url, requestPayload));
}
String results = "";
// Wait for the completion and get the result
for (CompletableFuture<String> C : future) {
results += C.join();
}
return results;
}
/* Send tasks to a specific workers with custom headers and return result */
public List<String> sendTasksToWorkers(List<String> workersAddresses, List<String> tasks, String headers) {
List<String> results = new ArrayList<>();
for (String address:workersAddresses) {
results.add(sendTaskToWorker(address, tasks, headers));
}
return results;
}
/* Send tasks to a specific worker with custom headers and return result */
private String sendTaskToWorker(String workerAddress, List<String> tasks, String headers) {
String url = workerAddress + "/task";
List<CompletableFuture<String>> future= new ArrayList<>();
for (String task:tasks) {
byte[] requestPayload = String.join(",", task).getBytes();
future.add(webClient.sendTask(url, requestPayload, headers));
}
String results= "";
// Wait for the completion and get the result
for (CompletableFuture<String> C:future) {
results+=C.join();
}
return results;
}
}
import java.util.Arrays;
import java.util.List;
public class Application {
private static final String WORKER_ADDRESS_1 = "http://localhost:8080/task";
public static void main(String[] args) {
Aggregator aggregator = new Aggregator();
String task1 = "10,200";
String task2 = "123456789,100000000000000,700000002342343";
String headers = "X-Debug: true";
List<String> results = aggregator.sendTasksToWorkers(Arrays.asList(WORKER_ADDRESS_1),
Arrays.asList(task2,task1));
for (String result : results) {
System.out.println(result);
}
List<String> resultsWithHeaders = aggregator.sendTasksToWorkers(Arrays.asList(WORKER_ADDRESS_1),
Arrays.asList(task2,task1), headers);
for (String result : resultsWithHeaders) {
System.out.println(result);
}
}
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
public class WebClient {
private HttpClient client;
public WebClient() {
this.client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();
}
/* Send task (post http request) asynchronously */
public CompletableFuture<String> sendTask(String url, byte[] requestPayload) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofByteArray(requestPayload))
.build();
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body);
}
/* Send task (post http request) asynchronously with custom headers*/
public CompletableFuture<String> sendTask(String url, byte[] requestPayload, String headers) {
String [] parts= headers.split(":");
String nameOfHeader=parts[0];
String value= parts[1];
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header(nameOfHeader, value)
.POST(HttpRequest.BodyPublishers.ofByteArray(requestPayload))
.build();
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse ->{
// Do something with the response headers if needed
// Return the complete HttpResponse object
return "Headers:\n"+HttpResponse.headers()+"\n Body:\n"+ HttpResponse.body();
});
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="HOME_LOG" value="logs/app.log"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${HOME_LOG}</file>
<append>true</append>
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</encoder>
</appender>
<!-- Log Level: ERROR, WARN, INFO, DEBUG, TRACE-->
<logger name="Client" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="HOME_LOG" value="logs/app.log"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${HOME_LOG}</file>
<append>true</append>
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</encoder>
</appender>
<!-- Log Level: ERROR, WARN, INFO, DEBUG, TRACE-->
<logger name="Client" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
\ No newline at end of file
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="httpserver" />
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="httpserver" options="--add-modules java.logging" />
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17 (2)" project-jdk-type="JavaSDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<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>org.example</groupId>
<artifactId>httpserver</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<logback.version>1.2.3</logback.version>
</properties>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
import com.sun.net.httpserver.*;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
public class WebServer {
static final Logger logger = Logger.getLogger("WebServer");
private static final String TASK_ENDPOINT = "/task";
private static final String Status_ENDPOINT = "/status";
private final int port;
private HttpServer server;
public WebServer(int port) {
this.port = port;
}
public static void main(String[] args) {
int serverPort = 8080;
if (args.length == 1) {
serverPort = Integer.parseInt(args[0]);
}
WebServer webServer = new WebServer(serverPort);
webServer.startServer();
System.out.println("Server is listening on port " + serverPort);
}
public void startServer() {
try {
this.server = HttpServer.create(new InetSocketAddress(port), 0);
} catch (IOException e) {
throw new RuntimeException(e);
}
HttpContext statusContext = server.createContext(Status_ENDPOINT);
HttpContext taskContext = server.createContext(TASK_ENDPOINT);
statusContext.setHandler(this::handleStatusCheckRequest);
taskContext.setHandler(this::handleTaskRequest);
server.setExecutor(Executors.newFixedThreadPool(8));
server.start();
}
private void handleTaskRequest(HttpExchange exchange) throws IOException {
if (!exchange.getRequestMethod().equalsIgnoreCase("post")) {
exchange.close();
return;
}
Headers headers = exchange.getRequestHeaders();
if (headers.containsKey("X-Test") && headers.get("X-Test").get(0).equalsIgnoreCase("true")) {
String dummyResp = "123\n";
sendResponse(dummyResp.getBytes(), exchange);
return;
}
boolean isDebugMode = false;
if (headers.containsKey("X-Debug") && headers.get("X-Debug").get(0).equalsIgnoreCase("true")) {
isDebugMode = true;
}
long startTime = System.nanoTime();
byte[] requestBytes = exchange.getRequestBody().readAllBytes();
byte[] responseBytes = calculateResponse(requestBytes);
long finishTime = System.nanoTime();
if (isDebugMode) {
String debugMessage = String.format("Operation took %d ns", finishTime - startTime);
exchange.getResponseHeaders().put("X-Debug-Info", Arrays.asList(debugMessage));
}
sendResponse(responseBytes, exchange);
}
private byte[] calculateResponse(byte[] requestBytes) {
String bodyString = new String(requestBytes);
String[] stringNumbers = bodyString.split(",");
BigInteger result = BigInteger.ONE;
for (String number : stringNumbers) {
BigInteger bigInteger = new BigInteger(number);
result = result.multiply(bigInteger);
}
return String.format("Result of the multiplication is %s\n", result).getBytes();
}
private void handleStatusCheckRequest(HttpExchange exchange) throws IOException {
if (!exchange.getRequestMethod().equalsIgnoreCase("get")) {
exchange.close();
return;
}
String responseMessage = "Server is alive\n";
sendResponse(responseMessage.getBytes(), exchange);
}
private void sendResponse(byte[] responseBytes, HttpExchange exchange) throws IOException {
exchange.sendResponseHeaders(200, responseBytes.length);
OutputStream outputStream = exchange.getResponseBody();
outputStream.write(responseBytes);
outputStream.flush();
outputStream.close();
exchange.close();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="HOME_LOG" value="logs/app.log"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${HOME_LOG}</file>
<append>true</append>
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</encoder>
</appender>
<!-- Log Level: ERROR, WARN, INFO, DEBUG, TRACE-->
<logger name="Server" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="HOME_LOG" value="logs/app.log"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${HOME_LOG}</file>
<append>true</append>
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</encoder>
</appender>
<!-- Log Level: ERROR, WARN, INFO, DEBUG, TRACE-->
<logger name="Server" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</logger>
<root level="error">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment