Skip to content
45 changes: 24 additions & 21 deletions src/main/java/ru/hh/school/stdlib/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,31 @@

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Launcher {
public static void main(String[] args) throws IOException {
String host;
int port;
try {
if (args.length == 0) {
host = "127.0.0.1";
port = 9129;
} else if (args.length == 3) {
host = args[1];
port = Integer.parseInt(args[2]);
} else {
throw new IllegalArgumentException();
}
} catch (Exception e) {
System.err.printf("Usage: %s [host port]%n", args[0]);
System.exit(1);
return; // попробуйте закомментировать этот return
}
InetSocketAddress addr = InetSocketAddress.createUnresolved(host, port);
public static void main(String[] args) throws IOException {
String host;
int port;
try {
if (args.length == 0) {
host = "127.0.0.1";
port = 9129;
} else if (args.length == 3) {
host = args[1];
port = Integer.parseInt(args[2]);
} else {
throw new IllegalArgumentException();
}
} catch (Exception e) {
System.err.printf("Usage: %s [host port]%n", args[0]);
System.exit(1);
return;
}

new Server(addr).run();
}
InetSocketAddress addr = InetSocketAddress.createUnresolved(host, port);
ExecutorService exec = Executors.newSingleThreadExecutor();
exec.execute(new Server(addr));
}
}
4 changes: 4 additions & 0 deletions src/main/java/ru/hh/school/stdlib/RecursiveException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package ru.hh.school.stdlib;

public class RecursiveException extends Exception {
}
58 changes: 47 additions & 11 deletions src/main/java/ru/hh/school/stdlib/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,53 @@

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Server {
public Server(InetSocketAddress addr) {
throw new UnsupportedOperationException();
}
public class Server implements Runnable {
private int serverPort = 4444;
private ServerSocket serverSocket = null;
private Substitutor3000 substitutor;
private int sleepTime = 0;

public void run() throws IOException {
throw new UnsupportedOperationException();
}
public Server(InetSocketAddress addr) {
this.serverPort = addr.getPort();
substitutor = new Substitutor3000();
}

public int getPort() {
throw new UnsupportedOperationException();
}
}
public void run() {
openServerSocket();
ExecutorService exec = Executors.newCachedThreadPool();
while(true){
Socket clientSocket;
try {
clientSocket = this.serverSocket.accept();
} catch (IOException e) {
throw new RuntimeException("Error accepting client connection", e);
}
exec.execute(new ServerThread(clientSocket, substitutor, this));
}
}

public int getPort() {
return serverPort;
}

private void openServerSocket() {
try {
this.serverSocket = new ServerSocket(this.serverPort);
} catch (IOException e) {
throw new RuntimeException("Cannot open port 8080", e);
}
}

public synchronized int getSleepTime() {
return sleepTime;
}

public synchronized void setSleepTime(int sleepTime) {
this.sleepTime = sleepTime;
}
}
94 changes: 94 additions & 0 deletions src/main/java/ru/hh/school/stdlib/ServerThread.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package ru.hh.school.stdlib;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.TimeUnit;

public class ServerThread implements Runnable{
private final static String SUCCESS_REQUEST = "OK\nconnection closed";
private final static String WRONG_REQUEST = "ERROR\nWrong request. Please try again.";
private final static String RECURSIVE_ERROR = "ERROR\nRecursive link detected";

private Socket clientSocket;
private Substitutor3000 substitutor;
private Server server;

public ServerThread(Socket clientSocket, Substitutor3000 substitutor, Server server) {
this.clientSocket = clientSocket;
this.substitutor = substitutor;
this.server = server;
}

public void run() {
try {
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine, outputLine;

while ((inputLine = in.readLine()) != null) {
outputLine = processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("EXIT"))
break;
}

out.close();
in.close();
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}

private String processInput(String inputLine) {
String[] input = inputLine.split("\\s");

if (input[0].equals("GET")) {
sleep();
String key = input[1];
String value;
try {
value = substitutor.get(key);
} catch (RecursiveException e) {
return RECURSIVE_ERROR;
}
return "VALUE\n" + value;
}
else if (input[0].equals("PUT")) {
sleep();
String key = input[1];
String value = "";
for (int i = 2; i < input.length; i++)
value += input[i];
substitutor.put(key, value);
return SUCCESS_REQUEST;
}
else if (input[0].equals("SET")) {
if (input[1].equals("SLEEP")) {
server.setSleepTime(Integer.parseInt(input[2]));
return SUCCESS_REQUEST;
}
else
return WRONG_REQUEST;
}
else if (input[0].equals("EXIT")) {
return "EXIT";
}
else {
return WRONG_REQUEST;
}
}

private void sleep() {
if (server.getSleepTime() != 0) {
try {
TimeUnit.MILLISECONDS.sleep(server.getSleepTime());
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
40 changes: 34 additions & 6 deletions src/main/java/ru/hh/school/stdlib/Substitutor3000.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
package ru.hh.school.stdlib;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Substitutor3000 {
public void put(String key, String value) {
throw new UnsupportedOperationException();
}
private Map<String,String> map = Collections.synchronizedMap(new HashMap<String, String>());
private ArrayList<String> keys = new ArrayList<String>();

public synchronized void put(String key, String value) {
map.put(key, value);
}

public synchronized String get(String key) throws RecursiveException {
String regex = "\\$\\{(\\w+)\\}";
String value = map.get(key);
if (value == null)
return "";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(value);

if (keys.contains(value))
throw new RecursiveException();
keys.add(value);
while (m.find()) {
value = value.replaceFirst(regex, get(m.group(1)));
m = p.matcher(value);
}
keys.remove(value);
if (!value.contains(" "))
value += " ";

public String get(String key) {
throw new UnsupportedOperationException();
}
return value;
}
}
80 changes: 40 additions & 40 deletions src/test/java/ru/hh/school/stdlib/BaseFunctionalTest.java
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
package ru.hh.school.stdlib;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

public class BaseFunctionalTest {
private static Server server;

protected BaseFunctionalTest() {
synchronized (BaseFunctionalTest.class) {
try {
if (server == null) {
server = new Server(new InetSocketAddress("127.0.0.1", 0));
new Thread(new Runnable() {
public void run() {
try {
server.run();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
Thread.sleep(100);
System.out.printf("Server started on port %d%n", server.getPort());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

protected Socket connect() {
try {
return new Socket("127.0.0.1", server.getPort());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package ru.hh.school.stdlib;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
public class BaseFunctionalTest {
private static Server server;
protected BaseFunctionalTest() {
synchronized (BaseFunctionalTest.class) {
try {
if (server == null) {
server = new Server(new InetSocketAddress("127.0.0.1", 4444));
new Thread(new Runnable() {
public void run() {
//try {
server.run();
//} catch (IOException e) {
//throw new RuntimeException(e);
// }
}
}).start();
Thread.sleep(100);
System.out.printf("Server started on port %d%n", server.getPort());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
protected Socket connect() {
try {
return new Socket("127.0.0.1", server.getPort());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
38 changes: 38 additions & 0 deletions src/test/java/ru/hh/school/stdlib/MultiConnection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ru.hh.school.stdlib;

import org.junit.Assert;
import org.junit.Test;

import java.io.*;
import java.net.Socket;

public class MultiConnection extends BaseFunctionalTest {

@Test
public void testMultiConnection() throws IOException {
long timePeriod = 2000;

Socket s1 = connect();
Socket s2 = connect();

Writer out1 = new PrintWriter(s1.getOutputStream());
BufferedReader in1 = new BufferedReader(new InputStreamReader(s1.getInputStream()));
Writer out2 = new PrintWriter(s2.getOutputStream());
BufferedReader in2 = new BufferedReader(new InputStreamReader(s2.getInputStream()));

out1.append("SET SLEEP " + timePeriod + "\n").flush();
Assert.assertEquals("OK", in1.readLine());
Assert.assertEquals("connection closed", in1.readLine());
long start = System.currentTimeMillis();
out1.append("GET k1\n").flush();
out2.append("GET k1\n").flush();
Assert.assertEquals("VALUE", in1.readLine());
Assert.assertEquals("", in1.readLine());
Assert.assertEquals("VALUE", in2.readLine());
Assert.assertEquals("", in2.readLine());
long end = System.currentTimeMillis();

Assert.assertTrue((end - start) < (timePeriod * 2));
System.out.println(end - start);
}
}
Loading