diff --git a/todo-list/src/main/java/org/todo/services/MySQLService.java b/todo-list/src/main/java/org/todo/services/MySQLService.java new file mode 100644 index 0000000..6a5c336 --- /dev/null +++ b/todo-list/src/main/java/org/todo/services/MySQLService.java @@ -0,0 +1,41 @@ +// Copyright (c) 2021, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +package org.todo.services; + +import org.todo.services.resource.ItemsResource; + +import javax.naming.NamingException; +import java.sql.*; + +public class MySQLService extends TodoService { + // create app table for MySQL + private static final String MYSQL_CREATE_TABLE = "create table ToDos (" + + "taskId INT NOT NULL AUTO_INCREMENT, " + + "task VARCHAR(200) NOT NULL, " + + "completed BOOLEAN NOT NULL DEFAULT 0," + + "constraint todo_pk PRIMARY KEY (taskId));"; + + @Override + public String getCreateTableStatement() { + return MYSQL_CREATE_TABLE; + } + + @Override + public boolean getComplete(ResultSet resultSet) throws SQLException { + return resultSet.getBoolean("completed"); + } + + @Override + public void update(int id, String status) { + try (Connection conn = ItemsResource.datasource().getConnection()) { + PreparedStatement statement = conn.prepareStatement(updateSql); + System.out.println(updateSql); + statement.setBoolean(1, Boolean.parseBoolean(status)); + statement.setInt(2, id); + statement.executeUpdate(); + } catch (SQLException | NamingException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/todo-list/src/main/java/org/todo/services/OracleDBService.java b/todo-list/src/main/java/org/todo/services/OracleDBService.java new file mode 100644 index 0000000..2b9ce9b --- /dev/null +++ b/todo-list/src/main/java/org/todo/services/OracleDBService.java @@ -0,0 +1,51 @@ +// Copyright (c) 2021, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +package org.todo.services; + +import org.todo.services.resource.ItemsResource; + +import javax.naming.NamingException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class OracleDBService extends TodoService { + // Create app table for OracleDB + private static final String ORACLEDB_CREATE_TABLE = "CREATE TABLE ToDos( " + + "taskId NUMBER GENERATED BY DEFAULT AS IDENTITY, " + + "task VARCHAR2(200) NOT NULL, " + + "completed NUMBER(1) DEFAULT 0 CHECK (completed in (0,1)), " + + "PRIMARY KEY(taskId));"; + + @Override + public String getCreateTableStatement() { + return ORACLEDB_CREATE_TABLE; + } + + @Override + boolean getComplete(ResultSet resultSet) throws SQLException { + return (resultSet.getInt("completed") != 0); + } + + @Override + public void update(int id, String status) { + try (Connection conn = ItemsResource.datasource().getConnection()) { + PreparedStatement statement = conn.prepareStatement(updateSql); + System.out.println(updateSql); + statement.setInt(0, completeFromBooleanString(status)); + statement.setLong(1, id); + statement.executeUpdate(); + } catch (SQLException | NamingException ex) { + throw new RuntimeException(ex); + } + } + + private int completeFromBooleanString(String status) { + if (status.equalsIgnoreCase("true")) { + return 1; + } + return 0; + } +} diff --git a/todo-list/src/main/java/org/todo/services/TodoService.java b/todo-list/src/main/java/org/todo/services/TodoService.java new file mode 100644 index 0000000..26aadaf --- /dev/null +++ b/todo-list/src/main/java/org/todo/services/TodoService.java @@ -0,0 +1,112 @@ +// Copyright (c) 2021, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. + +package org.todo.services; + +import org.todo.services.entity.Item; +import org.todo.services.resource.ItemsResource; + +import javax.naming.NamingException; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +// Handle database specific logic for ToDo app +public abstract class TodoService { + protected final static String selectSql = "select task, completed from ToDos where taskId = ?"; + protected final static String deleteSql = "delete from ToDos where taskId = ?"; + protected final static String insertSql = "insert into ToDos(task) values(?)"; + protected final static String updateSql = "update ToDos set completed = ? where taskId = ?"; + protected final static String getAllSql = "select taskId, task, completed from ToDos"; + + private static TodoService TODO_SERVICE = null; + + public static TodoService getDefault() { + if (TODO_SERVICE == null) { + String queryServiceClass = System.getenv("QUERY_SERVICE_CLASS"); + if (queryServiceClass == null) { + TODO_SERVICE = new MySQLService(); + } else { + try { + TODO_SERVICE = (TodoService) Class.forName(queryServiceClass).getConstructor().newInstance(); + } catch (Exception e) { + TODO_SERVICE = new MySQLService(); + } + } + + System.out.println("Created TODO Service: " + TODO_SERVICE.getClass().getName()); + } + + return TODO_SERVICE; + } + + public abstract String getCreateTableStatement(); + + public abstract void update(int id, String status); + + abstract boolean getComplete(ResultSet resultSet) throws SQLException; + + public List parseResults(ResultSet resultSet) throws SQLException { + List result = new ArrayList<>(); + while (resultSet.next()) { + int id = resultSet.getInt("taskId"); + String task = resultSet.getString("task"); + boolean complete = getComplete(resultSet); + result.add(new Item(id).desc(task).done(complete)); + } + + return result; + } + + public Item parseResult(ResultSet resultSet, int id) throws SQLException { + Item item = null; + if (resultSet.next()) { + String task = resultSet.getString("task"); + boolean complete = getComplete(resultSet); + item = new Item(id).desc(task).done(complete); + } + + return item; + } + + public void insert(String description) { + try (Connection conn = ItemsResource.datasource().getConnection()) { + PreparedStatement statement = conn.prepareStatement(insertSql); + statement.setString(1, description); + statement.executeUpdate(); + } catch (SQLException | NamingException ex) { + throw new RuntimeException(ex); + } + } + + public void delete(int id) { + try (Connection conn = ItemsResource.datasource().getConnection()) { + PreparedStatement statement = conn.prepareStatement(deleteSql); + statement.setInt(1, id); + statement.executeUpdate(); + } catch (SQLException | NamingException ex) { + throw new RuntimeException(ex); + } + } + + public Item getById(int id) { + try (Connection conn = ItemsResource.datasource().getConnection()) { + PreparedStatement statement = conn.prepareStatement(selectSql); + statement.setInt(1, id); + ResultSet results = statement.executeQuery(); + return parseResult(results, id); + } catch (SQLException | NamingException ex) { + throw new RuntimeException(ex); + } + } + + public List getAll() { + try (Connection conn = ItemsResource.datasource().getConnection()){ + Statement statement = conn.createStatement(); + ResultSet resultSet = statement.executeQuery(getAllSql); + return this.parseResults(resultSet); + } catch (SQLException | NamingException ex) { + throw new RuntimeException(ex); + } + } +} diff --git a/todo-list/src/main/java/org/todo/services/resource/ItemResource.java b/todo-list/src/main/java/org/todo/services/resource/ItemResource.java index 5b2212c..5c278cb 100644 --- a/todo-list/src/main/java/org/todo/services/resource/ItemResource.java +++ b/todo-list/src/main/java/org/todo/services/resource/ItemResource.java @@ -1,77 +1,41 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright (c) 2020, 2021, Oracle and/or its affiliates. // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. package org.todo.services.resource; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import javax.json.JsonObject; -import javax.naming.NamingException; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; - +import org.todo.services.TodoService; import org.todo.services.entity.Item; +import javax.json.JsonObject; +import javax.ws.rs.*; + @Path("/item") public class ItemResource { - - public final static String selectSql = "select task, completed from ToDos where taskId = %s"; - public final static String deleteSql = "delete from ToDos where taskId = %s"; - public final static String insertSql = "insert into ToDos(task, completed) values('%s', false);"; - public final static String updateSql = "update ToDos set completed = %s where taskId = %s"; + private static final TodoService TODO_SERVICE = TodoService.getDefault(); @GET @Path("/{id}") @Produces("application/json") - public JsonObject item(@PathParam("id") String id) { - Item result = null; - try (Connection conn = ItemsResource.datasource().getConnection()) { - Statement statement = conn.createStatement(); - String queryStr = String.format(selectSql, id); - System.out.println(queryStr); - ResultSet resultSet = statement.executeQuery(queryStr); - if (resultSet.next()) { - String task = resultSet.getString("task"); - boolean complete = resultSet.getBoolean("completed"); - result = new Item(Integer.parseInt(id)).desc(task).done(complete); - } - } catch (SQLException | NamingException ex) { - ex.printStackTrace(); - } + public JsonObject item(@PathParam("id") int id) { + Item result = TODO_SERVICE.getById(id); return result == null ? null : result.toJson(); } @DELETE @Path("/{id}") - public void delete(@PathParam("id") String id) { - runQuery(String.format(deleteSql, id)); + public void delete(@PathParam("id") int id) { + TODO_SERVICE.delete(id); } @PUT @Path("/{taskDescription}") public void addNewItem(@PathParam("taskDescription") String description) { - runQuery(String.format(insertSql, description)); + TODO_SERVICE.insert(description); } @PUT @Path("/{id}/{status}") - public void updateStatus(@PathParam("id") String id, @PathParam("status") String status) { - runQuery(String.format(updateSql, id, status)); - } - - private void runQuery(String query) { - try (Connection conn = ItemsResource.datasource().getConnection()) { - Statement statement = conn.createStatement(); - System.out.println(query); - statement.executeUpdate(query); - } catch (SQLException | NamingException ex) { - ex.printStackTrace(); - } + public void updateStatus(@PathParam("id") int id, @PathParam("status") String status) { + TODO_SERVICE.update(id, status); } } diff --git a/todo-list/src/main/java/org/todo/services/resource/ItemsResource.java b/todo-list/src/main/java/org/todo/services/resource/ItemsResource.java index 341d148..6c29150 100644 --- a/todo-list/src/main/java/org/todo/services/resource/ItemsResource.java +++ b/todo-list/src/main/java/org/todo/services/resource/ItemsResource.java @@ -1,14 +1,11 @@ -// Copyright (c) 2020, Oracle and/or its affiliates. +// Copyright (c) 2020, 2021, Oracle and/or its affiliates. // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. package org.todo.services.resource; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; +import org.todo.services.TodoService; +import org.todo.services.entity.Item; + import javax.json.Json; import javax.json.JsonArray; import javax.json.JsonArrayBuilder; @@ -20,8 +17,9 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; - -import org.todo.services.entity.Item; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; /** * REST service for the To-Do list application using MySQL DB. @@ -31,34 +29,16 @@ @Path("/items/") @Produces(MediaType.APPLICATION_JSON) public class ItemsResource { - + private static final TodoService TODO_SERVICE = TodoService.getDefault(); public static DataSource datasource() throws NamingException { InitialContext ctx = new InitialContext(); return (DataSource) ctx.lookup("jdbc/ToDoDB"); } - public List items() { - List result = new ArrayList<>(); - - try (Connection conn = datasource().getConnection()){ - Statement statement = conn.createStatement(); - ResultSet resultSet = statement.executeQuery("select taskId, task, completed from ToDos"); - while (resultSet.next()) { - int id = resultSet.getInt("taskId"); - String task = resultSet.getString("task"); - boolean complete = resultSet.getBoolean("completed"); - result.add(new Item(id).desc(task).done(complete)); - } - } catch (SQLException | NamingException ex) { - ex.printStackTrace(); - } - return result; - } - @GET public JsonArray itemsJson() { JsonArrayBuilder result = Json.createArrayBuilder(); - for (Item item : items()) { + for (Item item : TODO_SERVICE.getAll()) { result.add(item.toJson()); } return result.build(); @@ -89,20 +69,14 @@ public Response initTable() { try (Connection conn = datasource().getConnection()){ Statement stmt = conn.createStatement(); - String createTable = "create table ToDos (" + - "taskId INT NOT NULL AUTO_INCREMENT, " + - "task VARCHAR(200) NOT NULL, " + - "completed BOOLEAN," + - "constraint todo_pk PRIMARY KEY (taskId));"; + String createTable = TODO_SERVICE.getCreateTableStatement(); System.out.println(createTable); stmt.executeUpdate(createTable); String[] tasks = {"Install Verrazzano", "Move ToDo List to the cloud", "Celebrate", "Clean off my desk"}; for (String task : tasks) { - String insert = String.format(ItemResource.insertSql, task); - System.out.println(insert); - stmt.executeUpdate(insert); + TODO_SERVICE.insert(task); } } catch (SQLException | NamingException ex) {