Skip to content

Commit

Permalink
Merge pull request #22 from vlasival/task_2_1_2
Browse files Browse the repository at this point in the history
task_2_1_2
  • Loading branch information
vlasival committed Jun 7, 2024
2 parents 345678c + b69c809 commit bfa3855
Show file tree
Hide file tree
Showing 20 changed files with 1,323 additions and 0 deletions.
9 changes: 9 additions & 0 deletions task_2_1_2/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# Linux start script should use lf
/gradlew text eol=lf

# These are Windows script files and should use crlf
*.bat text eol=crlf

7 changes: 7 additions & 0 deletions task_2_1_2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
build

bin
56 changes: 56 additions & 0 deletions task_2_1_2/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.6/userguide/building_java_projects.html in the Gradle documentation.
*/

plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
id 'jacoco'
}

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}

dependencies {
// Use JUnit Jupiter for testing.
testImplementation libs.junit.jupiter

testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// This dependency is used by the application.
implementation libs.guava

compileOnly 'org.projectlombok:lombok:1.18.32'
annotationProcessor 'org.projectlombok:lombok:1.18.32'

testCompileOnly 'org.projectlombok:lombok:1.18.32'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.32'
}

// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

application {
// Define the main class for the application.
mainClass = 'org.example.App'
}

tasks.named('test') {
// Use JUnit Platform for unit tests.
useJUnitPlatform()
}

jacocoTestReport {
reports {
xml.required = true
}
}
14 changes: 14 additions & 0 deletions task_2_1_2/app/src/main/java/org/prime/Message.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.prime;

import java.io.Serializable;
import java.util.List;
import lombok.Data;

/**
* Class represents a message wandering on the network.
*/
@Data
public class Message implements Serializable {
private String type;
private List<Integer> data;
}
183 changes: 183 additions & 0 deletions task_2_1_2/app/src/main/java/org/prime/PrimeClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package org.prime;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;

/**
* PrimeClient class that implements a client for distributed checking of numbers for primality.
*/
public class PrimeClient {

private SocketChannel socket;
private ByteBuffer buffer;

/**
* PrimeClient constructor.
*
* @param address server address
* @param port server port
*/
public PrimeClient(String address, int port) {
try {
socket = SocketChannel.open(new InetSocketAddress(address, port));
socket.configureBlocking(false);
buffer = ByteBuffer.allocate(PrimeUtils.BUFFER_SIZE);
System.out.println("Channel bound and configured on IP \'" + address
+ "\' and port " + port);
} catch (IOException e) {
e.printStackTrace();
System.out.println("Failed to bind socket");
}
}

/**
* Client launch.
*
* @throws IOException if an I/O error occurs
*/
public void start() throws IOException {
sendMessage(createMessage("REQUEST", null));
int requestAttempts = 0;

while (true) {
buffer.clear();
int bytesRead = socket.read(buffer);
if (bytesRead == -1) {
System.out.println("Server is down. Shutting down...");
return;
}
if (bytesRead > 0) {
buffer.flip();
try {
Message message = readMessageFromBuffer();
String messageType = message.getType();
switch (messageType) {
case "TASK":
handleTask(message.getData());
requestAttempts = 0;
break;
case "EXIT":
System.out.println("Tasks done. Exiting program...");
return;
default:
System.out.println("Unknown message type. Synchronize types.");
break;
}
} catch (ClassNotFoundException e) {
if (requestAttempts >= 3) {
System.out.println("Too many attempts to receive message. Aborting...");
return;
}
System.out.println("Error casting received message to Message class.");
sendMessage(createMessage("REQUEST", null));
requestAttempts++;
}
buffer.clear();
}

// Sleep for a short duration to prevent busy-waiting
try {
Thread.sleep(1);
} catch (InterruptedException e) {
System.out.println("Client thread interrupted. Exiting...");
return;
}
}
}

/**
* Creating a message to send in network.
*
* @param type message type
* @param data message data
* @return message
*/
private Message createMessage(String type, List<Integer> data) {
Message message = new Message();
message.setType(type);
message.setData(data);
return message;
}

/**
* Sending message to the server method.
*
* @param message message to send
* @throws IOException if an I/O error occurs
*/
private void sendMessage(Message message) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(message);
objectOutputStream.flush();
byte[] data = byteArrayOutputStream.toByteArray();
ByteBuffer buffer = ByteBuffer.wrap(data);
socket.write(buffer);
}

/**
* Read a message from client buffer.
*
* @return readed message
* @throws IOException if an I/O error occurs
* @throws ClassNotFoundException if class of buffer data don't cast to message class
*/
private Message readMessageFromBuffer() throws IOException, ClassNotFoundException {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffer.array());
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return (Message) objectInputStream.readObject();
}

/**
* List primality checking.
*
* @param nums list of numbers to check
* @throws IOException if an I/O error occurs
*/
private void handleTask(List<Integer> nums) throws IOException {
for (Integer number : nums) {
if (!isPrime(number)) {
sendMessage(createMessage("RESULT", null));
return;
}
}
sendMessage(createMessage("RESULT", new ArrayList<>()));
}

/**
* Number primality checking.
*
* @param number number to check
* @return true if prime, false otherwise
*/
public boolean isPrime(int number) {
if (number <= 1) {
return false;
}
for (int i = 2; i <= Math.sqrt(number); i++) {
if (number % i == 0) {
return false;
}
}
return true;
}

/**
* Entry point to start a client.
*
* @param args command line args
* @throws IOException if an I/O error occurs
*/
public static void main(String[] args) throws IOException {
PrimeClient client = new PrimeClient("localhost", 5000);
client.start();
}
}
Loading

0 comments on commit bfa3855

Please sign in to comment.