Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

todo-challenge solution #7

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 192 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?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>dhrim</groupId>
<artifactId>todo-challenge</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>

<!-- maven plugin version -->
<plugin.compiler.version>3.1</plugin.compiler.version>

<!-- library version -->
<jackson.version>1.9.11</jackson.version>
<jetty-server.version>9.2.3.v20140905</jetty-server.version>
<jersy.version>2.25</jersy.version>
<jersey-json.version>1.19.3</jersey-json.version>
<jersey-guice>1.19.3</jersey-guice>
<guice.version>3.0</guice.version>
<slf4j.version>1.7.22</slf4j.version>
<logback.version>1.1.8</logback.version>
<lombok.version>1.16.12</lombok.version>
<mapdb.version>3.0.2</mapdb.version>
<guava.version>20.0</guava.version>

<!-- test library version -->
<junit.version>4.12</junit.version>
<httpclient.version>3.1</httpclient.version>
<hamcrest-junit.version>2.0.0.0</hamcrest-junit.version>

</properties>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${plugin.compiler.version}</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>



<dependencies>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>




<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty-server.version}</version>
</dependency>


<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty-server.version}</version>
</dependency>


<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersy.version}</version>
</dependency>


<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersy.version}</version>
</dependency>


<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
<version>${jersy.version}</version>
</dependency>


<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>${jersey-json.version}</version>
</dependency>

<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-guice</artifactId>
<version>${jersey-json.version}</version>
<exclusions>
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</exclusion>
</exclusions>
</dependency>


<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>${jackson.version}</version>
</dependency>

<!-- DI injection framework -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>${guice.version}</version>
</dependency>

<!-- common util -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>



<!-- file repository -->
<dependency>
<groupId>org.mapdb</groupId>
<artifactId>mapdb</artifactId>
<version>${mapdb.version}</version>
</dependency>


<!-- log -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>


<!-- http client for test -->
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>${httpclient.version}</version>
<scope>test</scope>
</dependency>

<!-- test framework -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-junit</artifactId>
<version>${hamcrest-junit.version}</version>
<scope>test</scope>
</dependency>


</dependencies>

</project>
118 changes: 118 additions & 0 deletions src/main/java/dhrim/zeplchallenge/todo/AbstractMapBasedTodoRepo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package dhrim.zeplchallenge.todo;

import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Singleton;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Singleton
@Slf4j
public abstract class AbstractMapBasedTodoRepo implements TodoRepo {

// todo.id -> Todo
private Map<String, Todo> todoMap;

// todo.id -> Map<taskId, Task>
private Map<String, Map<String, Task>> taskMapMap;

/** return Map which store todoId to Todo */
protected abstract Map<String, Todo> getTodoMapInstance();

/** return Map which store todoId to Map<taskId, Task> */
protected abstract Map<String, Map<String, Task>> getTaskMapMapInstance();

protected void initIfNot() {
if(todoMap !=null) { return; }
todoMap = getTodoMapInstance();
taskMapMap = getTaskMapMapInstance();
}

@VisibleForTesting
void clear_for_test() {
// could be null if initIfNot() not called.
if(todoMap ==null) { return; }
todoMap.clear();
taskMapMap.clear();
}

@Override
public List<Todo> getTodoList() {
initIfNot();
return new ArrayList(todoMap.values());
}

@Override
public Todo getTodo(String todoId) {
initIfNot();
if(todoId==null) { throw new IllegalArgumentException("todoId is null."); }
return todoMap.get(todoId);
}

@Override
public Todo saveOrUpdate(Todo todo) {
initIfNot();
if(todo.getId()==null) { throw new IllegalArgumentException("todo.id is null. todo="+todo); }
todoMap.put(todo.getId(), todo);
return getTodo(todo.getId());
}


@Override
public List<Task> getTaskList(String todoId) {
initIfNot();
if(todoId==null) { throw new IllegalArgumentException("todoId is null."); }
return new ArrayList(taskMapMap.get(todoId).values());
}

@Override
public Task getTask(String todoId, String taskId) {
initIfNot();
if(todoId==null) { throw new IllegalArgumentException("todoId is null."); }
if(taskId==null) { throw new IllegalArgumentException("taskId is null."); }
Map<String, Task> taskMap = taskMapMap.get(todoId);
if(taskMap==null) { return null; }
Task task = taskMap.get(taskId);
if(task==null) { throw new IllegalArgumentException("task not found. todoId="+todoId+", taskId="+taskId); }
return task;
}

@Override
public Task saveOrUpdate(String todoId, Task task) {
initIfNot();
if(todoId==null) { throw new IllegalArgumentException("todoId is null."); }
if(task.getId()==null) { throw new IllegalArgumentException("task.id is null. task="+task); }
Map<String, Task> taskMap = taskMapMap.get(todoId);
if(taskMap==null) {
taskMap = new HashMap<>();
}
taskMap.put(task.getId(), task);
// TODO : it's not good specific code related with MapDb.
// taskMapMap is clone instance when using MapDb.
taskMapMap.put(todoId, taskMap);
return getTask(todoId, task.getId());
}


@Override
public void removeTodo(String todoId) {
initIfNot();
if(todoId==null) { throw new IllegalArgumentException("todoId is null."); }
todoMap.remove(todoId);
}

@Override
public void removeTask(String todoId, String taskId) {
initIfNot();
if(todoId==null) { throw new IllegalArgumentException("todoId is null."); }
if(taskId==null) { throw new IllegalArgumentException("taskId is null."); }
Map<String, Task> taskMap = taskMapMap.get(todoId);
if(taskMap==null) { return; }
taskMap.remove(taskId);
}

}
11 changes: 11 additions & 0 deletions src/main/java/dhrim/zeplchallenge/todo/FailedMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package dhrim.zeplchallenge.todo;

import lombok.Data;

import javax.xml.bind.annotation.XmlRootElement;

@Data
@XmlRootElement
public class FailedMessage {
private String message;
}
40 changes: 40 additions & 0 deletions src/main/java/dhrim/zeplchallenge/todo/GuiceDiBinding.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dhrim.zeplchallenge.todo;

import com.sun.jersey.api.core.PackagesResourceConfig;
import com.sun.jersey.guice.JerseyServletModule;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;

/**
* Bind jersey resource classes and other service classes for Guice DI injection.
*
* Jersey resource classes are auto scanned from BASE_PACKAGE recursively.
* Other service classes are configured manually not scanned.
*/
public class GuiceDiBinding extends JerseyServletModule {

// value is like "dhrim.zeplchallenge.todo"
private static final String BASE_PACKAGE = Main.class.getPackage().getName();

@Override
protected void configureServlets() {

configureResourceClasses();
configureServiceClasses();

serve("/*").with(GuiceContainer.class);

}

private void configureResourceClasses() {
PackagesResourceConfig resourceConfig = new PackagesResourceConfig(BASE_PACKAGE);
for (Class<?> resource : resourceConfig.getClasses()) {
bind(resource);
}
}

private void configureServiceClasses() {
bind(TodoService.class);
bind(TodoRepo.class).to(MapDbTodoRepo.class);
}

}
Loading