├── WebContent ├── META-INF │ └── MANIFEST.MF ├── WEB-INF │ └── web.xml ├── index.jsp └── assets │ └── todo.js ├── media └── documentdb-java-application │ └── image1.png ├── src └── com │ └── microsoft │ └── azure │ └── cosmos │ └── sample │ ├── dao │ ├── TodoDaoFactory.java │ ├── CosmosClientFactory.java │ ├── TodoDao.java │ ├── MockDao.java │ └── DocDbDao.java │ ├── model │ └── TodoItem.java │ ├── controller │ └── TodoItemController.java │ └── ApiServlet.java ├── CONTRIBUTING.md ├── .gitignore ├── LICENSE ├── .project ├── pom.xml ├── test └── com │ └── microsoft │ └── azure │ └── cosmos │ └── sample │ └── controller │ └── TodoItemControllerTest.java └── README.md /WebContent/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Class-Path: 3 | 4 | -------------------------------------------------------------------------------- /media/documentdb-java-application/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/documentdb-java-todo-app/HEAD/media/documentdb-java-application/image1.png -------------------------------------------------------------------------------- /src/com/microsoft/azure/cosmos/sample/dao/TodoDaoFactory.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample.dao; 2 | 3 | public class TodoDaoFactory { 4 | private static TodoDao myTodoDao = new DocDbDao(); 5 | 6 | public static TodoDao getDao() { 7 | return myTodoDao; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /WebContent/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | azure-cosmos-java-sample 4 | 5 | index.html 6 | index.htm 7 | index.jsp 8 | default.html 9 | default.htm 10 | default.jsp 11 | 12 | -------------------------------------------------------------------------------- /src/com/microsoft/azure/cosmos/sample/dao/CosmosClientFactory.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample.dao; 2 | 3 | import com.azure.cosmos.ConsistencyLevel; 4 | import com.azure.cosmos.CosmosClient; 5 | import com.azure.cosmos.CosmosClientBuilder; 6 | 7 | public class CosmosClientFactory { 8 | private static final String HOST = "[ACCOUNT HOST NAME]"; 9 | private static final String MASTER_KEY = "[ACCOUNT KEY]"; 10 | 11 | private static CosmosClient cosmosClient = new CosmosClientBuilder() 12 | .endpoint(HOST) 13 | .key(MASTER_KEY) 14 | .consistencyLevel(ConsistencyLevel.EVENTUAL) 15 | .buildClient(); 16 | 17 | public static CosmosClient getCosmosClient() { 18 | return cosmosClient; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Azure samples 2 | 3 | Thank you for your interest in contributing to Azure samples! 4 | 5 | ## Ways to contribute 6 | 7 | You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways: 8 | 9 | - Submit feedback on [this sample page](https://azure.microsoft.com/documentation/samples/cosmos-java-todo-app/) whether it was helpful or not. 10 | - Submit issues through [issue tracker](https://github.com/Azure-Samples/cosmos-java-todo-app/issues) on GitHub. We are actively monitoring the issues and improving our samples. 11 | - If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | pom.xml.tag 3 | pom.xml.releaseBackup 4 | pom.xml.versionsBackup 5 | pom.xml.next 6 | release.properties 7 | dependency-reduced-pom.xml 8 | buildNumber.properties 9 | .mvn/timing.properties 10 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 11 | .mvn/wrapper/maven-wrapper.jar 12 | 13 | # Compiled class file 14 | *.class 15 | 16 | # Log file 17 | *.log 18 | 19 | # BlueJ files 20 | *.ctxt 21 | 22 | # idea files 23 | /.idea/ 24 | 25 | # Mobile Tools for Java (J2ME) 26 | .mtj.tmp/ 27 | 28 | # Package Files # 29 | *.jar 30 | *.war 31 | *.nar 32 | *.ear 33 | *.zip 34 | *.tar.gz 35 | *.rar 36 | 37 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 38 | hs_err_pid* 39 | 40 | # Eclipse project file 41 | *.project 42 | 43 | # Maven autogenerated classpath 44 | *.classpath 45 | 46 | #VSCode Directories 47 | /*.settings/ 48 | /*.vscode/ 49 | /target/ 50 | 51 | *.iml 52 | -------------------------------------------------------------------------------- /src/com/microsoft/azure/cosmos/sample/dao/TodoDao.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample.dao; 2 | 3 | import java.util.List; 4 | 5 | import com.microsoft.azure.cosmos.sample.model.TodoItem; 6 | 7 | public interface TodoDao { 8 | /** 9 | * @return A list of TodoItems 10 | */ 11 | public List readTodoItems(); 12 | 13 | /** 14 | * @param todoItem 15 | * @return whether the todoItem was persisted. 16 | */ 17 | public TodoItem createTodoItem(TodoItem todoItem); 18 | 19 | /** 20 | * @param id 21 | * @return the TodoItem 22 | */ 23 | public TodoItem readTodoItem(String id); 24 | 25 | /** 26 | * @param id 27 | * @return the TodoItem 28 | */ 29 | public TodoItem updateTodoItem(String id, boolean isComplete); 30 | 31 | /** 32 | * 33 | * @param id 34 | * @return whether the delete was successful. 35 | */ 36 | public boolean deleteTodoItem(String id); 37 | } 38 | -------------------------------------------------------------------------------- /src/com/microsoft/azure/cosmos/sample/model/TodoItem.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample.model; 2 | 3 | //@Data 4 | //@Builder 5 | public class TodoItem { 6 | private String entityType; 7 | private String category; 8 | private boolean complete; 9 | private String id; 10 | private String name; 11 | 12 | public String getCategory() { 13 | return category; 14 | } 15 | 16 | public void setCategory(String category) { 17 | this.category = category; 18 | } 19 | 20 | public String getEntityType() { 21 | return entityType; 22 | } 23 | 24 | public void setEntityType(String entityType) { 25 | this.entityType = entityType; 26 | } 27 | 28 | public boolean isComplete() { 29 | return complete; 30 | } 31 | 32 | public void setComplete(boolean complete) { 33 | this.complete = complete; 34 | } 35 | 36 | public String getId() { 37 | return id; 38 | } 39 | 40 | public void setId(String id) { 41 | this.id = id; 42 | } 43 | 44 | public String getName() { 45 | return name; 46 | } 47 | 48 | public void setName(String name) { 49 | this.name = name; 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | azure-cosmos-java-sample 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.m2e.core.maven2Nature 36 | org.eclipse.jem.workbench.JavaEMFNature 37 | org.eclipse.wst.common.modulecore.ModuleCoreNature 38 | org.eclipse.wst.common.project.facet.core.nature 39 | org.eclipse.jdt.core.javanature 40 | org.eclipse.wst.jsdt.core.jsNature 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/com/microsoft/azure/cosmos/sample/dao/MockDao.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample.dao; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import lombok.NonNull; 9 | 10 | import com.microsoft.azure.cosmos.sample.model.TodoItem; 11 | 12 | public class MockDao implements TodoDao { 13 | private final Map todoItemMap; 14 | 15 | public MockDao() { 16 | todoItemMap = new HashMap(); 17 | } 18 | 19 | @Override 20 | public TodoItem createTodoItem(@NonNull TodoItem todoItem) { 21 | if (todoItem.getId() == null || todoItem.getId().isEmpty()) { 22 | todoItem.setId(generateId()); 23 | } 24 | todoItemMap.put(todoItem.getId(), todoItem); 25 | return todoItem; 26 | } 27 | 28 | @Override 29 | public TodoItem readTodoItem(@NonNull String id) { 30 | return todoItemMap.get(id); 31 | } 32 | 33 | @Override 34 | public List readTodoItems() { 35 | return new ArrayList(todoItemMap.values()); 36 | } 37 | 38 | @Override 39 | public TodoItem updateTodoItem(String id, boolean isComplete) { 40 | todoItemMap.get(id).setComplete(isComplete); 41 | return todoItemMap.get(id); 42 | } 43 | 44 | @Override 45 | public boolean deleteTodoItem(@NonNull String id) { 46 | todoItemMap.remove(id); 47 | return true; 48 | } 49 | 50 | private String generateId() { 51 | return new Integer(todoItemMap.size()).toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/com/microsoft/azure/cosmos/sample/controller/TodoItemController.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample.controller; 2 | 3 | import java.util.List; 4 | import java.util.UUID; 5 | 6 | import lombok.NonNull; 7 | 8 | import com.microsoft.azure.cosmos.sample.dao.TodoDao; 9 | import com.microsoft.azure.cosmos.sample.dao.TodoDaoFactory; 10 | import com.microsoft.azure.cosmos.sample.model.TodoItem; 11 | 12 | public class TodoItemController { 13 | public static TodoItemController getInstance() { 14 | if (todoItemController == null) { 15 | todoItemController = new TodoItemController(TodoDaoFactory.getDao()); 16 | } 17 | return todoItemController; 18 | } 19 | 20 | private static TodoItemController todoItemController; 21 | 22 | private final TodoDao todoDao; 23 | 24 | TodoItemController(TodoDao todoDao) { 25 | this.todoDao = todoDao; 26 | } 27 | 28 | public TodoItem createTodoItem(@NonNull String name, 29 | @NonNull String category, boolean isComplete) { 30 | TodoItem todoItem = new TodoItem(); 31 | 32 | todoItem.setName(name); 33 | todoItem.setCategory(category); 34 | todoItem.setComplete(isComplete); 35 | todoItem.setId(UUID.randomUUID().toString()); 36 | 37 | return todoDao.createTodoItem(todoItem); 38 | } 39 | 40 | public boolean deleteTodoItem(@NonNull String id) { 41 | return todoDao.deleteTodoItem(id); 42 | } 43 | 44 | public TodoItem getTodoItemById(@NonNull String id) { 45 | return todoDao.readTodoItem(id); 46 | } 47 | 48 | public List getTodoItems() { 49 | return todoDao.readTodoItems(); 50 | } 51 | 52 | public TodoItem updateTodoItem(@NonNull String id, boolean isComplete) { 53 | return todoDao.updateTodoItem(id, isComplete); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/com/microsoft/azure/cosmos/sample/ApiServlet.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.ServletException; 6 | import javax.servlet.annotation.WebServlet; 7 | import javax.servlet.http.HttpServlet; 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | import com.google.gson.Gson; 12 | import com.microsoft.azure.cosmos.sample.controller.TodoItemController; 13 | 14 | /** 15 | * API Frontend Servlet 16 | */ 17 | @WebServlet("/api") 18 | public class ApiServlet extends HttpServlet { 19 | // API Keys 20 | public static final String API_METHOD = "method"; 21 | 22 | // API Methods 23 | public static final String CREATE_TODO_ITEM = "createTodoItem"; 24 | public static final String GET_TODO_ITEMS = "getTodoItems"; 25 | public static final String UPDATE_TODO_ITEM = "updateTodoItem"; 26 | 27 | // API Parameters 28 | public static final String TODO_ITEM_ID = "todoItemId"; 29 | public static final String TODO_ITEM_NAME = "todoItemName"; 30 | public static final String TODO_ITEM_CATEGORY = "todoItemCategory"; 31 | public static final String TODO_ITEM_COMPLETE = "todoItemComplete"; 32 | 33 | public static final String MESSAGE_ERROR_INVALID_METHOD = "{'error': 'Invalid method'}"; 34 | 35 | private static final long serialVersionUID = 1L; 36 | private static final Gson gson = new Gson(); 37 | 38 | @Override 39 | protected void doGet(HttpServletRequest request, 40 | HttpServletResponse response) throws ServletException, IOException { 41 | 42 | String apiResponse = MESSAGE_ERROR_INVALID_METHOD; 43 | 44 | TodoItemController todoItemController = TodoItemController 45 | .getInstance(); 46 | 47 | String id = request.getParameter(TODO_ITEM_ID); 48 | String name = request.getParameter(TODO_ITEM_NAME); 49 | String category = request.getParameter(TODO_ITEM_CATEGORY); 50 | String itemComplete = request.getParameter(TODO_ITEM_COMPLETE); 51 | boolean isComplete = itemComplete!= null && itemComplete.equalsIgnoreCase("true"); 52 | 53 | switch (request.getParameter(API_METHOD)) { 54 | case CREATE_TODO_ITEM: 55 | apiResponse = gson.toJson(todoItemController.createTodoItem(name, 56 | category, isComplete)); 57 | break; 58 | case GET_TODO_ITEMS: 59 | apiResponse = gson.toJson(todoItemController.getTodoItems()); 60 | break; 61 | case UPDATE_TODO_ITEM: 62 | apiResponse = gson.toJson(todoItemController.updateTodoItem(id, 63 | isComplete)); 64 | break; 65 | default: 66 | break; 67 | } 68 | 69 | response.setCharacterEncoding("UTF-8"); 70 | response.getWriter().println(apiResponse); 71 | } 72 | 73 | @Override 74 | protected void doPost(HttpServletRequest request, 75 | HttpServletResponse response) throws ServletException, IOException { 76 | doGet(request, response); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /WebContent/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 2 | 3 | 4 | 5 | 6 | 7 | Azure Cosmos Java Sample 8 | 9 | 10 | 11 | 12 | 18 | 19 | 20 | 21 | 28 | 29 | 30 |
31 |

My ToDo List

32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
NameCategoryComplete
48 | 49 | 50 |
51 |
52 | 53 |
54 |
55 | 56 |
57 | 58 |
59 | 60 | 61 |
62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 | 70 |
71 | 72 |
73 | 74 |
75 |
76 | 77 | 78 |
79 |
80 | 81 |
82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | azure-cosmos-java-sample 4 | azure-cosmos-java-sample 5 | 0.0.1-SNAPSHOT 6 | war 7 | 8 | src 9 | 10 | 11 | maven-compiler-plugin 12 | 3.1 13 | 14 | 1.7 15 | 1.7 16 | 17 | 18 | 19 | maven-war-plugin 20 | 2.4 21 | 22 | WebContent 23 | false 24 | 25 | 26 | 27 | org.apache.maven.plugins 28 | maven-eclipse-plugin 29 | 2.8 30 | 31 | 32 | 33 | org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | javax.servlet 43 | javax.servlet-api 44 | 3.0.1 45 | 46 | 47 | com.google.code.gson 48 | gson 49 | 2.3 50 | 51 | 52 | junit 53 | junit 54 | 4.11 55 | 56 | 57 | org.projectlombok 58 | lombok 59 | 1.14.4 60 | 61 | 62 | org.apache.logging.log4j 63 | log4j-slf4j-impl 64 | 2.13.0 65 | test 66 | 67 | 68 | 69 | org.apache.logging.log4j 70 | log4j-api 71 | 2.11.1 72 | test 73 | 74 | 75 | 76 | org.slf4j 77 | slf4j-jdk14 78 | 1.7.28 79 | 80 | 81 | com.azure 82 | azure-cosmos 83 | 4.11.0 84 | 85 | 86 | -------------------------------------------------------------------------------- /test/com/microsoft/azure/cosmos/sample/controller/TodoItemControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample.controller; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.assertNull; 6 | 7 | import java.util.List; 8 | import java.util.Random; 9 | 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | 13 | import com.microsoft.azure.cosmos.sample.dao.DocDbDao; 14 | import com.microsoft.azure.cosmos.sample.model.TodoItem; 15 | 16 | public class TodoItemControllerTest { 17 | private static final String anyTodoItemName = "myName"; 18 | private static final String anyTodoItemCategory = "myCategory"; 19 | private static final boolean anyTodoItemComplete = true; 20 | 21 | private TodoItemController todoItemController; 22 | 23 | @Before 24 | public void setup() { 25 | todoItemController = new TodoItemController(new DocDbDao()); 26 | } 27 | 28 | @Test 29 | public void testCreateTodoItem() { 30 | // Count how many items are exist in the datastore. 31 | List listOfTodoItems = todoItemController.getTodoItems(); 32 | int numberOfExistingItems = listOfTodoItems.size(); 33 | 34 | // Create a random new item. 35 | Random randy = new Random(); 36 | int randomInt = randy.nextInt(); 37 | 38 | String testTodoItemId = todoItemController.createTodoItem( 39 | anyTodoItemName + randomInt, anyTodoItemCategory + randomInt, 40 | randomInt % 2 == 0).getId(); 41 | 42 | // Check one of the randomly created items. 43 | TodoItem testTodoItem = todoItemController 44 | .getTodoItemById(testTodoItemId); 45 | 46 | assertNotNull(testTodoItem); 47 | assertEquals(anyTodoItemName + randomInt, testTodoItem.getName()); 48 | assertEquals(anyTodoItemCategory + randomInt, 49 | testTodoItem.getCategory()); 50 | assertEquals(randomInt % 2 == 0, testTodoItem.isComplete()); 51 | 52 | // Check that the total item makes sense. 53 | listOfTodoItems = todoItemController.getTodoItems(); 54 | assertEquals(numberOfExistingItems + 1, listOfTodoItems.size()); 55 | } 56 | 57 | @Test 58 | public void testDeleteTodoItem() { 59 | // Create an item to delete. 60 | String testTodoItemId = todoItemController.createTodoItem( 61 | anyTodoItemName, anyTodoItemCategory, anyTodoItemComplete) 62 | .getId(); 63 | 64 | // Sanity Check 65 | TodoItem actualTodoItem = todoItemController 66 | .getTodoItemById(testTodoItemId); 67 | assertNotNull(actualTodoItem); 68 | 69 | // Delete the item. 70 | todoItemController.deleteTodoItem(testTodoItemId); 71 | 72 | // Check to see if the item was deleted 73 | actualTodoItem = todoItemController.getTodoItemById(testTodoItemId); 74 | assertNull(actualTodoItem); 75 | } 76 | 77 | @Test 78 | public void testUpdateTodoItem() { 79 | // Create an item to update. 80 | boolean oldValue = anyTodoItemComplete; 81 | TodoItem testTodoItem = todoItemController.createTodoItem( 82 | anyTodoItemName, anyTodoItemCategory, oldValue); 83 | 84 | // Sanity Check 85 | boolean actualValue = todoItemController.getTodoItemById( 86 | testTodoItem.getId()).isComplete(); 87 | assertEquals(oldValue, actualValue); 88 | 89 | // Update whether the item is complete. 90 | boolean newValue = !oldValue; 91 | todoItemController.updateTodoItem(testTodoItem.getId(), newValue); 92 | 93 | // Check to see if the value was updated. 94 | actualValue = todoItemController.getTodoItemById(testTodoItem.getId()) 95 | .isComplete(); 96 | assertEquals(newValue, actualValue); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | languages: 4 | - java 5 | - javascript 6 | products: 7 | - azure 8 | description: "The sample code in this Github repository demonstrates how to create a simple application using Java and Azure CosmosDB." 9 | urlFragment: cosmos-java-todo-app 10 | --- 11 | 12 | # A Simple Todo List Application built w/ Java + Azure CosmosDB 13 | 14 | The sample code in this Github repository demonstrates how to create a simple application using Java and Azure CosmosDB. 15 | 16 | For a complete end-to-end walkthrough of creating the application, please visit the following [Azure documentation page](https://azure.microsoft.com/documentation/articles/cosmos-java-application/). 17 | 18 | ![My ToDo List Java application](./media/cosmos-java-application/image1.png) 19 | 20 | 21 | ##Requirements 22 | Before you begin this application development tutorial, you must have the following: 23 | 24 | - An active Azure CosmosDB account. 25 | - If you don't have an account, you can find instructions on how to create one on our [Azure documentation page](https://docs.microsoft.com/azure/cosmos-db/create-cosmosdb-resources-portal). 26 | - [Java Development Kit (JDK) 7+](http://www.oracle.com/technetwork/java/javase/downloads/index.html). 27 | - [Eclipse IDE for Java EE Developers.](http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/lunasr1) 28 | 29 | If you're installing these tools for the first time, coreservlets.com provides a walk-through of the installation process in the Quick Start section of their [Tutorial: Installing TomCat7 and Using it with Eclipse](http://www.coreservlets.com/Apache-Tomcat-Tutorial/tomcat-7-with-eclipse.html) article. 30 | 31 | ##Running the Code Sample 32 | 33 | All the samples in this tutorial are included in the cosmos-java-todoapp project on [GitHub](https://github.com/Azure-Samples/cosmos-java-todoapp). To import the todo project into Eclipse, ensure you have the software and resources listed in the [Requirements](#Requirements) section, then do the following: 34 | 35 | 1. Install [Project Lombok](http://projectlombok.org/). Lombok is used to generate constructors, getters, setters in the project. Once you have downloaded the lombok.jar file, double-click it to install it or install it from the command line. 36 | 2. If Eclipse is open, close it and restart it to load Lombok. 37 | 3. In Eclipse, on the **File** menu, click **Import**. 38 | 4. In the **Import** window, click **Git**, click **Projects from Git**, and then click **Next**. 39 | 5. On the **Select Repository Source** screen, click **Clone URI**. 40 | 6. On the **Source Git Repository** screen, in the **URI** box, enter `https://github.com/Azure-Samples/cosmos-java-todoapp.git`, and then click **Next**. 41 | 7. On the **Branch Selection** screen, ensure that **master** is selected, and then click **Next**. 42 | 8. On the **Local Destination** screen, click **Browse** to select a folder where the repository can be copied, and then click **Next**. 43 | 9. On the **Select a wizard to use for importing projects** screen, ensure that **Import existing projects** is selected, and then click **Next**. 44 | 10. On the **Import Projects** screen, unselect the **CosmosDB** project, and then click **Finish**. The CosmosDB project contains the CosmosDB Java SDK, which we will add as a dependency instead. 45 | 11. In **Project Explorer**, navigate to `\src\com.microsoft.azure.cosmos.sample.dao\CosmosClientFactory.java` and replace the `HOST` and `MASTER_KEY` values with the `URI` and `PRIMARY KEY` for your CosmosDB account, and then save the file. For more information, see [Step 1. Create a CosmosDB database account](https://docs.microsoft.com/azure/cosmos-db/sql-api-java-application#CreateDB). 46 | 12. In **Project Explorer**, right click the **azure-cosmos-java-sample**, click **Build Path**, and then click **Configure Build Path**. 47 | 13. On the **Java Build Path** screen, in the right pane, select the **Libraries** tab, and then click **Add External JARs**. Navigate to the location of the lombok.jar file, and click **Open**, and then click **OK**. 48 | 14. Use step 12 to open the **Properties** window again, and then in the left pane click **Targeted Runtimes**. 49 | 15. On the **Targeted Runtimes** screen, click **New**, select **Apache Tomcat v7.0**, and then click **OK**. 50 | 16. Use step 12 to open the **Properties** window again, and then in the left pane click **Project Facets**. 51 | 17. On the **Project Facets** screen, select **Dynamic Web Module** and **Java**, and then click **OK**. 52 | 18. On the **Servers** tab at the bottom of the screen, right-click **Tomcat v7.0 Server at localhost** and then click **Add and Remove**. 53 | 19. On the **Add and Remove** window, move **azure-cosmos-java-sample** to the **Configured** box, and then click **Finish**. 54 | 20. In the **Server** tab, right-click **Tomcat v7.0 Server at localhost**, and then click **Restart**. 55 | 21. In a browser, navigate to `http://localhost:8080/azure-cosmos-java-sample/` and start adding to your task list. Note that if you changed your default port values, change `8080` to the value you selected. 56 | -------------------------------------------------------------------------------- /WebContent/assets/todo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ToDo App 3 | */ 4 | 5 | var todoApp = { 6 | /* 7 | * API methods to call Java backend. 8 | */ 9 | apiEndpoint: "api", 10 | 11 | createTodoItem: function(name, category, isComplete) { 12 | $.post(todoApp.apiEndpoint, { 13 | "method": "createTodoItem", 14 | "todoItemName": name, 15 | "todoItemCategory": category, 16 | "todoItemComplete": isComplete 17 | }, 18 | function(data) { 19 | var todoItem = data; 20 | todoApp.addTodoItemToTable(todoItem.id, todoItem.name, todoItem.category, todoItem.complete); 21 | }, 22 | "json"); 23 | }, 24 | 25 | getTodoItems: function() { 26 | $.post(todoApp.apiEndpoint, { 27 | "method": "getTodoItems" 28 | }, 29 | function(data) { 30 | var todoItemArr = data; 31 | $.each(todoItemArr, function(index, value) { 32 | todoApp.addTodoItemToTable(value.id, value.name, value.category, value.complete); 33 | }); 34 | }, 35 | "json"); 36 | }, 37 | 38 | updateTodoItem: function(id, isComplete) { 39 | $.post(todoApp.apiEndpoint, { 40 | "method": "updateTodoItem", 41 | "todoItemId": id, 42 | "todoItemComplete": isComplete 43 | }, 44 | function(data) {}, 45 | "json"); 46 | }, 47 | 48 | /* 49 | * UI Methods 50 | */ 51 | addTodoItemToTable: function(id, name, category, isComplete) { 52 | var rowColor = isComplete ? "active" : "warning"; 53 | 54 | todoApp.ui_table().append($("") 55 | .append($("").text(name)) 56 | .append($("").text(category)) 57 | .append($("") 58 | .append($("") 59 | .attr("type", "checkbox") 60 | .attr("id", id) 61 | .attr("checked", isComplete) 62 | .attr("class", "isComplete") 63 | )) 64 | .addClass(rowColor) 65 | ); 66 | }, 67 | 68 | /* 69 | * UI Bindings 70 | */ 71 | bindCreateButton: function() { 72 | todoApp.ui_createButton().click(function() { 73 | todoApp.createTodoItem(todoApp.ui_createNameInput().val(), todoApp.ui_createCategoryInput().val(), false); 74 | todoApp.ui_createNameInput().val(""); 75 | todoApp.ui_createCategoryInput().val(""); 76 | }); 77 | }, 78 | 79 | bindUpdateButton: function() { 80 | todoApp.ui_updateButton().click(function() { 81 | // Disable button temporarily. 82 | var myButton = $(this); 83 | var originalText = myButton.text(); 84 | $(this).text("Updating..."); 85 | $(this).prop("disabled", true); 86 | 87 | // Call api to update todo items. 88 | $.each(todoApp.ui_updateId(), function(index, value) { 89 | todoApp.updateTodoItem(value.name, value.value); 90 | $(value).remove(); 91 | }); 92 | 93 | // Re-enable button. 94 | setTimeout(function() { 95 | myButton.prop("disabled", false); 96 | myButton.text(originalText); 97 | }, 500); 98 | }); 99 | }, 100 | 101 | bindUpdateCheckboxes: function() { 102 | todoApp.ui_table().on("click", ".isComplete", function(event) { 103 | var checkboxElement = $(event.currentTarget); 104 | var rowElement = $(event.currentTarget).parents('tr'); 105 | var id = checkboxElement.attr('id'); 106 | var isComplete = checkboxElement.is(':checked'); 107 | 108 | // Togle table row color 109 | if (isComplete) { 110 | rowElement.addClass("active"); 111 | rowElement.removeClass("warning"); 112 | } else { 113 | rowElement.removeClass("active"); 114 | rowElement.addClass("warning"); 115 | } 116 | 117 | // Update hidden inputs for update panel. 118 | todoApp.ui_updateForm().children("input[name='" + id + "']").remove(); 119 | 120 | todoApp.ui_updateForm().append($("") 121 | .attr("type", "hidden") 122 | .attr("class", "updateComplete") 123 | .attr("name", id) 124 | .attr("value", isComplete)); 125 | 126 | }); 127 | }, 128 | 129 | /* 130 | * UI Elements 131 | */ 132 | ui_createNameInput: function() { 133 | return $(".todoForm #inputItemName"); 134 | }, 135 | 136 | ui_createCategoryInput: function() { 137 | return $(".todoForm #inputItemCategory"); 138 | }, 139 | 140 | ui_createButton: function() { 141 | return $(".todoForm button"); 142 | }, 143 | 144 | ui_table: function() { 145 | return $(".todoList table tbody"); 146 | }, 147 | 148 | ui_updateButton: function() { 149 | return $(".todoUpdatePanel button"); 150 | }, 151 | 152 | ui_updateForm: function() { 153 | return $(".todoUpdatePanel form"); 154 | }, 155 | 156 | ui_updateId: function() { 157 | return $(".todoUpdatePanel .updateComplete"); 158 | }, 159 | 160 | /* 161 | * Install the TodoApp 162 | */ 163 | install: function() { 164 | todoApp.bindCreateButton(); 165 | todoApp.bindUpdateButton(); 166 | todoApp.bindUpdateCheckboxes(); 167 | 168 | todoApp.getTodoItems(); 169 | } 170 | }; 171 | 172 | $(document).ready(function() { 173 | todoApp.install(); 174 | }); 175 | -------------------------------------------------------------------------------- /src/com/microsoft/azure/cosmos/sample/dao/DocDbDao.java: -------------------------------------------------------------------------------- 1 | package com.microsoft.azure.cosmos.sample.dao; 2 | 3 | import com.azure.cosmos.CosmosClient; 4 | import com.azure.cosmos.CosmosContainer; 5 | import com.azure.cosmos.CosmosDatabase; 6 | import com.azure.cosmos.CosmosException; 7 | import com.azure.cosmos.implementation.Utils; 8 | import com.azure.cosmos.models.CosmosContainerProperties; 9 | import com.azure.cosmos.models.CosmosContainerResponse; 10 | import com.azure.cosmos.models.CosmosDatabaseResponse; 11 | import com.azure.cosmos.models.CosmosItemRequestOptions; 12 | import com.azure.cosmos.models.CosmosQueryRequestOptions; 13 | import com.azure.cosmos.models.FeedResponse; 14 | import com.azure.cosmos.models.PartitionKey; 15 | import com.fasterxml.jackson.core.JsonProcessingException; 16 | import com.fasterxml.jackson.databind.JsonNode; 17 | import com.fasterxml.jackson.databind.ObjectMapper; 18 | import com.fasterxml.jackson.databind.node.ObjectNode; 19 | import com.google.gson.Gson; 20 | import com.microsoft.azure.cosmos.sample.model.TodoItem; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | public class DocDbDao implements TodoDao { 26 | // The name of our database. 27 | private static final String DATABASE_ID = "TestDB"; 28 | 29 | // The name of our collection. 30 | private static final String CONTAINER_ID = "TestCollection"; 31 | 32 | // We'll use Gson for POJO <=> JSON serialization for this example. 33 | private static Gson gson = new Gson(); 34 | 35 | // The Cosmos DB Client 36 | private static CosmosClient cosmosClient = CosmosClientFactory 37 | .getCosmosClient(); 38 | 39 | // The Cosmos DB database 40 | private static CosmosDatabase cosmosDatabase = null; 41 | 42 | // The Cosmos DB container 43 | private static CosmosContainer cosmosContainer = null; 44 | 45 | // For POJO/JsonNode interconversion 46 | private static final ObjectMapper OBJECT_MAPPER = Utils.getSimpleObjectMapper(); 47 | 48 | @Override 49 | public TodoItem createTodoItem(TodoItem todoItem) { 50 | // Serialize the TodoItem as a JSON Document. 51 | 52 | JsonNode todoItemJson = OBJECT_MAPPER.valueToTree(todoItem); 53 | 54 | ((ObjectNode) todoItemJson).put("entityType", "todoItem"); 55 | 56 | try { 57 | // Persist the document using the DocumentClient. 58 | todoItemJson = 59 | getContainerCreateResourcesIfNotExist() 60 | .createItem(todoItemJson) 61 | .getItem(); 62 | } catch (CosmosException e) { 63 | System.out.println("Error creating TODO item.\n"); 64 | e.printStackTrace(); 65 | return null; 66 | } 67 | 68 | 69 | try { 70 | 71 | return OBJECT_MAPPER.treeToValue(todoItemJson, TodoItem.class); 72 | //return todoItem; 73 | } catch (Exception e) { 74 | System.out.println("Error deserializing created TODO item.\n"); 75 | e.printStackTrace(); 76 | 77 | return null; 78 | } 79 | 80 | } 81 | 82 | @Override 83 | public TodoItem readTodoItem(String id) { 84 | // Retrieve the document by id using our helper method. 85 | JsonNode todoItemJson = getDocumentById(id); 86 | 87 | if (todoItemJson != null) { 88 | // De-serialize the document in to a TodoItem. 89 | try { 90 | return OBJECT_MAPPER.treeToValue(todoItemJson, TodoItem.class); 91 | } catch (JsonProcessingException e) { 92 | System.out.println("Error deserializing read TODO item.\n"); 93 | e.printStackTrace(); 94 | 95 | return null; 96 | } 97 | } else { 98 | return null; 99 | } 100 | } 101 | 102 | @Override 103 | public List readTodoItems() { 104 | 105 | List todoItems = new ArrayList(); 106 | 107 | String sql = "SELECT * FROM root r WHERE r.entityType = 'todoItem'"; 108 | int maxItemCount = 1000; 109 | int maxDegreeOfParallelism = 1000; 110 | int maxBufferedItemCount = 100; 111 | 112 | CosmosQueryRequestOptions options = new CosmosQueryRequestOptions(); 113 | options.setMaxBufferedItemCount(maxBufferedItemCount); 114 | options.setMaxDegreeOfParallelism(maxDegreeOfParallelism); 115 | options.setQueryMetricsEnabled(false); 116 | 117 | int error_count = 0; 118 | int error_limit = 10; 119 | 120 | String continuationToken = null; 121 | do { 122 | 123 | for (FeedResponse pageResponse : 124 | getContainerCreateResourcesIfNotExist() 125 | .queryItems(sql, options, JsonNode.class) 126 | .iterableByPage(continuationToken, maxItemCount)) { 127 | 128 | continuationToken = pageResponse.getContinuationToken(); 129 | 130 | for (JsonNode item : pageResponse.getElements()) { 131 | 132 | try { 133 | todoItems.add(OBJECT_MAPPER.treeToValue(item, TodoItem.class)); 134 | } catch (JsonProcessingException e) { 135 | if (error_count < error_limit) { 136 | error_count++; 137 | if (error_count >= error_limit) { 138 | System.out.println("\n...reached max error count.\n"); 139 | } else { 140 | System.out.println("Error deserializing TODO item JsonNode. " + 141 | "This item will not be returned."); 142 | e.printStackTrace(); 143 | } 144 | } 145 | } 146 | 147 | } 148 | } 149 | 150 | } while (continuationToken != null); 151 | 152 | return todoItems; 153 | } 154 | 155 | @Override 156 | public TodoItem updateTodoItem(String id, boolean isComplete) { 157 | // Retrieve the document from the database 158 | JsonNode todoItemJson = getDocumentById(id); 159 | 160 | // You can update the document as a JSON document directly. 161 | // For more complex operations - you could de-serialize the document in 162 | // to a POJO, update the POJO, and then re-serialize the POJO back in to 163 | // a document. 164 | ((ObjectNode) todoItemJson).put("complete", isComplete); 165 | 166 | try { 167 | // Persist/replace the updated document. 168 | todoItemJson = 169 | getContainerCreateResourcesIfNotExist() 170 | .replaceItem(todoItemJson, id, new PartitionKey(id), new CosmosItemRequestOptions()) 171 | .getItem(); 172 | } catch (CosmosException e) { 173 | System.out.println("Error updating TODO item.\n"); 174 | e.printStackTrace(); 175 | return null; 176 | } 177 | 178 | // De-serialize the document in to a TodoItem. 179 | try { 180 | return OBJECT_MAPPER.treeToValue(todoItemJson, TodoItem.class); 181 | } catch (JsonProcessingException e) { 182 | System.out.println("Error deserializing updated item.\n"); 183 | e.printStackTrace(); 184 | 185 | return null; 186 | } 187 | } 188 | 189 | @Override 190 | public boolean deleteTodoItem(String id) { 191 | // CosmosDB refers to documents by self link rather than id. 192 | 193 | // Query for the document to retrieve the self link. 194 | JsonNode todoItemJson = getDocumentById(id); 195 | 196 | try { 197 | // Delete the document by self link. 198 | getContainerCreateResourcesIfNotExist() 199 | .deleteItem(id, new PartitionKey(id), new CosmosItemRequestOptions()); 200 | } catch (CosmosException e) { 201 | System.out.println("Error deleting TODO item.\n"); 202 | e.printStackTrace(); 203 | return false; 204 | } 205 | 206 | return true; 207 | } 208 | 209 | /* 210 | 211 | private CosmosDatabase getTodoDatabase() { 212 | if (databaseCache == null) { 213 | // Get the database if it exists 214 | List databaseList = cosmosClient 215 | .queryDatabases( 216 | "SELECT * FROM root r WHERE r.id='" + DATABASE_ID 217 | + "'", null).getQueryIterable().toList(); 218 | 219 | if (databaseList.size() > 0) { 220 | // Cache the database object so we won't have to query for it 221 | // later to retrieve the selfLink. 222 | databaseCache = databaseList.get(0); 223 | } else { 224 | // Create the database if it doesn't exist. 225 | try { 226 | CosmosDatabase databaseDefinition = new CosmosDatabase(); 227 | databaseDefinition.setId(DATABASE_ID); 228 | 229 | databaseCache = cosmosClient.createDatabase( 230 | databaseDefinition, null).getResource(); 231 | } catch (CosmosException e) { 232 | // TODO: Something has gone terribly wrong - the app wasn't 233 | // able to query or create the collection. 234 | // Verify your connection, endpoint, and key. 235 | e.printStackTrace(); 236 | } 237 | } 238 | } 239 | 240 | return databaseCache; 241 | } 242 | 243 | */ 244 | 245 | private CosmosContainer getContainerCreateResourcesIfNotExist() { 246 | 247 | try { 248 | 249 | if (cosmosDatabase == null) { 250 | CosmosDatabaseResponse cosmosDatabaseResponse = cosmosClient.createDatabaseIfNotExists(DATABASE_ID); 251 | cosmosDatabase = cosmosClient.getDatabase(cosmosDatabaseResponse.getProperties().getId()); 252 | } 253 | 254 | } catch (CosmosException e) { 255 | // TODO: Something has gone terribly wrong - the app wasn't 256 | // able to query or create the collection. 257 | // Verify your connection, endpoint, and key. 258 | System.out.println("Something has gone terribly wrong - " + 259 | "the app wasn't able to create the Database.\n"); 260 | e.printStackTrace(); 261 | } 262 | 263 | try { 264 | 265 | if (cosmosContainer == null) { 266 | CosmosContainerProperties properties = new CosmosContainerProperties(CONTAINER_ID, "/id"); 267 | CosmosContainerResponse cosmosContainerResponse = cosmosDatabase.createContainerIfNotExists(properties); 268 | cosmosContainer = cosmosDatabase.getContainer(cosmosContainerResponse.getProperties().getId()); 269 | } 270 | 271 | } catch (CosmosException e) { 272 | // TODO: Something has gone terribly wrong - the app wasn't 273 | // able to query or create the collection. 274 | // Verify your connection, endpoint, and key. 275 | System.out.println("Something has gone terribly wrong - " + 276 | "the app wasn't able to create the Container.\n"); 277 | e.printStackTrace(); 278 | } 279 | 280 | return cosmosContainer; 281 | } 282 | 283 | private JsonNode getDocumentById(String id) { 284 | 285 | String sql = "SELECT * FROM root r WHERE r.id='" + id + "'"; 286 | int maxItemCount = 1000; 287 | int maxDegreeOfParallelism = 1000; 288 | int maxBufferedItemCount = 100; 289 | 290 | CosmosQueryRequestOptions options = new CosmosQueryRequestOptions(); 291 | options.setMaxBufferedItemCount(maxBufferedItemCount); 292 | options.setMaxDegreeOfParallelism(maxDegreeOfParallelism); 293 | options.setQueryMetricsEnabled(false); 294 | 295 | List itemList = new ArrayList(); 296 | 297 | String continuationToken = null; 298 | do { 299 | for (FeedResponse pageResponse : 300 | getContainerCreateResourcesIfNotExist() 301 | .queryItems(sql, options, JsonNode.class) 302 | .iterableByPage(continuationToken, maxItemCount)) { 303 | 304 | continuationToken = pageResponse.getContinuationToken(); 305 | 306 | for (JsonNode item : pageResponse.getElements()) { 307 | itemList.add(item); 308 | } 309 | } 310 | 311 | } while (continuationToken != null); 312 | 313 | if (itemList.size() > 0) { 314 | return itemList.get(0); 315 | } else { 316 | return null; 317 | } 318 | } 319 | 320 | } 321 | --------------------------------------------------------------------------------