├── .gitignore ├── .gitpod.yml ├── README.md ├── pom.xml ├── todobackend-cassandra ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── datastax │ │ │ └── sample │ │ │ ├── TodoBackendApplication.java │ │ │ ├── conf │ │ │ ├── CassandraDriverConfig.java │ │ │ ├── OpenApiDocumentationConfig.java │ │ │ └── WebConfig.java │ │ │ ├── model │ │ │ ├── Task.java │ │ │ ├── TaskBody.java │ │ │ ├── TaskResource.java │ │ │ └── TodoAppSchema.java │ │ │ ├── objectmapper │ │ │ ├── TaskDao.java │ │ │ ├── TaskDaoMapper.java │ │ │ └── TaskEntity.java │ │ │ ├── repository │ │ │ ├── TodoListRepository.java │ │ │ ├── TodoListRepositoryCassandraDriverImpl.java │ │ │ ├── TodoListRepositoryInMemoryImpl.java │ │ │ ├── TodoListRepositoryObjectMapperImpl.java │ │ │ └── TodoListRepositorySpringDataImpl.java │ │ │ ├── resources │ │ │ ├── HomeController.java │ │ │ └── TodoListRestController.java │ │ │ └── springdata │ │ │ ├── TaskSpringData.java │ │ │ └── TaskSpringDataRepository.java │ └── resources │ │ ├── application.conf │ │ ├── application.yml │ │ ├── banner.txt │ │ ├── logback.xml │ │ └── sample-data.cql │ └── test │ ├── java │ └── com │ │ └── datastax │ │ └── samples │ │ └── astra │ │ ├── ConnectivityToAstraExplicitTest.java │ │ ├── ConnectivityToAstraWithConfTest.java │ │ ├── CreateSchemaInAstraTest.java │ │ ├── CrudWithCassandraDriverIntegrationTest.java │ │ └── CrudWithObjectMapperTest.java │ └── resources │ ├── application_test.conf │ └── logback-test.xml └── z-materials ├── images ├── astra-create-2.png ├── astra-create-3.png ├── astra-create-4.png ├── astra-create-5.png ├── astra-create-6.png ├── astra-create-7.png ├── astra-create-login.png ├── astra-create-register.png ├── backend-doc.png ├── backend-ok.png ├── describe-output-cqlconsole.png ├── describe-output-studio.png ├── gitpod-home.png ├── gitpod-updated.png ├── gitpod-upload-files.png ├── home.png ├── import-project-eclipse.png ├── intellij-import-1.png ├── intellij-import-2.png ├── launch-studio-home.png ├── launch-studio-import.png ├── launch-studio-open.png ├── launch-studio.png ├── linux32.png ├── locate-cqlconsole.png ├── locate-studio.png ├── mac32.png ├── realbackend-test.png ├── splash.png ├── todobackend-output-client.png ├── todobackend-output-host.png ├── todobackend-runclient.png ├── todobackend-runtest.png ├── todobackend-swagger-test.png ├── todobackend.png ├── todomvc.png ├── welldone.jpg └── windows32.png ├── notebooks └── datastax-studio-notebook.tar └── presentation.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse conf file 2 | .settings 3 | .classpath 4 | .project 5 | .cache 6 | 7 | # idea conf files 8 | .idea 9 | *.ipr 10 | *.iws 11 | *.iml 12 | 13 | # building 14 | target 15 | build 16 | tmp 17 | dist 18 | 19 | # misc 20 | .DS_Store 21 | 22 | .factorypath 23 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - init: mvn install -Dmaven.test.skip=true 3 | 4 | ports: 5 | - port: 8080 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ✨ Building Microservice for Apache Cassandra™ ✨ 3 | 4 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/DataStax-Academy/microservices-java-workshop-online) 5 | [![License Apache2](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0) 6 | [![Discord](https://img.shields.io/discord/685554030159593522)](https://discord.com/widget?id=685554030159593522&theme=dark) 7 | 8 | *"In this repository, you'll find everything you need related to the **Cassandra Developer Workshop Build Java Microservices for Apache Cassandra**. [The first live stream will be June 17th](https://www.youtube.com/watch?v=KAcZg6l9QTw). Past this date the `README.MD` will be updated with the recording. Feel free to bookmark this page for future reference, Enjoy"!* - The Developer Advocates Team. 9 | 10 | ![SplashScreen](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/splash.png?raw=true) 11 | 12 | `Cassandra Developer Workshops` are an interactive experience. Advocates share knowledge about Apache Cassandra™ databases and you interact with them through chats *([youtube](https://www.youtube.com/channel/UCAIQY251avaMv7bBv5PCo-A) and [discord](https://discord.com/widget?id=685554030159593522&theme=dark))*, quizzes (menti.com), and exercises. 13 | 14 | Today we are creating the Todo Application with storage in Apache Cassandra™. 15 | 16 | ![Home](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/home.png?raw=true) 17 | 18 | 19 | # Table of Content 20 | For simplicity all exercise instructions are listed in a single `README.MD` document. As it is quite long we provide a table of contents after each chapter so you can go back to it. 21 | 22 | | Sections | Material Description 23 | |---|---| 24 | | **Slide deck** | [Slidedeck for the workshop](z-materials/presentation.pdf) | 25 | | **1. Bootstrapping** | [Setup your environment](#1-bootstrapping) | 26 | | **2. Run the Todo Application** | [Run the Todo Application](#2-run-the-todo-application) | 27 | | **3. Create your Astra instance** | [Create your Astra instance](#3-create-your-astra-instance) | 28 | | **4. Connectivity to Astra** | [Connectivity to Cassandra](#4-connectivity-to-astra) | 29 | | **5. CRUD Repository** | [Implement CRUD Repository](#5-crud-repository) | 30 | | **6. CRUD Repository Object Mapper** | [Test Object Mapper](#6-crud-repository-with-object-mapper) | 31 | | **7. CRUD Repository Spring Data** | [Test with Spring DATA](#7-crud-repository-with-spring-data) | 32 | 33 | ## 1. Bootstrapping 34 | 35 | There are 2 ways to do the exercises, **locally** on your computer and with a **cloud-based IDE named Gitpod.** We recommend you to use your laptop in order to save code modifications and come back later. In both cases you should start by cloning the repository and download everything (including slides). 36 | 37 | - ### Option A - Work with a 100% Cloud-based Environment ☁️ 38 | 39 | **✅ Open gitpod** : [Gitpod](https://www.gitpod.io/) is an IDE 100% online based on Eclipse Theia. To initialize your environment simply click on the button below *(CTRL + Click to open in new tab)* 40 | 41 | [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/DataStax-Academy/microservices-java-workshop-online) 42 | 43 | Target url looks like `https://..gitpod.io/#/workspace/microservices-java-workshop-online`. These URL's are dynamic and we cannot provide clickable links in advance. You will need to copy-paste `.` as we will insert them in each URL during the exercises. 44 | 45 | ``` 46 | ⚠️ By default Autosaved is not enabled in Gitpod. Don't forget to save your modifications with CTRL+S 47 | ``` 48 | 49 | **👁️ Expected output** 50 | 51 | ![SplashScreen](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/gitpod-home.png?raw=true) 52 | 53 | **That's it.** Gitpod provides all tools we will need today including `Maven` and exporting port `8080`. At initialization of the workspace we schedule a `mvn clean install` to download dependencies. You can still download the repository and bookmark it as all materials including slides are included. 54 | 55 | - ### Option B - Work with Local Environment 💻 56 | 57 | This part is dedicated to people running the exercises on their laptop. You can skip it and go directly to [2. Run the Todo Application](#2-run-the-todo-application) if you are using gitpod. 58 | 59 | **✅ (local env) Clone the repository :** : With `git` or through the web UI clone the repo 60 | ```bash 61 | # Clone the current repository 62 | git clone https://github.com/DataStax-Academy/microservices-java-workshop-online.git 63 | 64 | # Access the proper folder 65 | cd microservices-java-workshop-online 66 | ``` 67 | 68 | **✅ (local env) Install Java (JDK 11 +)** Pick the proper infos based on your operating system 69 | - ![Windows](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/windows32.png?raw=true) Please use the following tutorial [Installation of the JDK on Microsoft Windows Platforms](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-microsoft-windows-platforms.html#GUID-A7E27B90-A28D-4237-9383-A58B416071CA) 70 | - ![linux](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/linux32.png?raw=true) Please use the following tutorial [Installation of the JDK on Linux Platform Platforms](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-linux-platforms.html#GUID-737A84E4-2EFF-4D38-8E60-3E29D1B884B8) 71 | - ![osx](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/mac32.png?raw=true) Please use the following tutorial [Installation of the JDK on MACOS Platforms](https://docs.oracle.com/en/java/javase/11/install/installation-jdk-macos.html#GUID-2FE451B0-9572-4E38-A1A5-568B77B146DE) or with [homebrew](https://docs.brew.sh/Installation): 72 | ```bash 73 | brew cask install java 74 | ``` 75 | 76 | **✅ (local env) Install Maven** 77 | - ![Windows](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/windows32.png?raw=true) Please use the following tutorial [How to install Maven on Windows](https://mkyong.com/maven/how-to-install-maven-in-windows) 78 | - ![linux](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/linux32.png?raw=true). For CentOS you can use: `sudo yum install maven` 79 | - ![osx](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/mac32.png?raw=true) For MacOS you can use `brew install maven` 80 | 81 | Validate installation 82 | ```bash 83 | mvn -v 84 | ``` 85 | 86 | **👁️ Expected output** 87 | ```bash 88 | Apache Maven 3.6.0 (97c98ec64a1fdfee7767ce5ffb20918da4f719f3; 2018-10-24T20:41:47+02:00) 89 | Maven home: /usr/local/Cellar/maven/3.6.0/libexec 90 | Java version: 12, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/openjdk-12.jdk/Contents/Home 91 | Default locale: en_FR, platform encoding: UTF-8 92 | OS name: "mac os x", version: "10.15.3", arch: "x86_64", family: "mac" 93 | ``` 94 | 95 | **✅ (local env) Install an IDE** 96 | 97 | Pick and install your favourite Java IDE. Here are some propositions without preference order. 98 | 99 | | Tools | Download link 100 | |---|---| 101 | | **Eclipse STS** | 📥[Download Eclipse Spring Tools Suite](https://spring.io/tools#main) 102 | | **Jetbrains IntelliJ** | 📥[Download IntelliJ](https://www.jetbrains.com/idea/download/index.html) 103 | | **Core Eclipse** | 📥[Download Eclipse](https://www.eclipse.org/downloads/) 104 | | **Visual Studio Code** | 📥[Downlowd Visual Code](https://code.visualstudio.com/Download) 105 | 106 | 107 | [🏠back to table of content](#table-of-content) 108 | 109 | ## 2. Run the Todo Application 110 | 111 | **TodoMVC** is a fabulous community contribution that helps developers compare frameworks on the basis of actual project code, not just claims and anecdotes. TodoMVC is an immensely valuable attempt at a difficult problem - providing a structured way of comparing JS libraries and frameworks. 112 | 113 | ![TodoMVC](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/todomvc.png?raw=true) 114 | 115 | **✅ Step 2a. Visit [TodoMVC.com](http://todomvc.com/) to discover what we are building today** : We want you to see what it look like before starting anything. So simply access the URL [http://todomvc.com/](http://todomvc.com/) and browse. You will see that there are multiple implementations, pick one of those and test it live in your browser. 116 | 117 | 118 | **Todo-Backend** is a shared example to showcase backend tech stacks. The Todo-Backend project defines a simple web API spec - for managing a todo list. Contributors implement that spec using various tech stacks. Those implementations are cataloged below. A spec runner verifies that each contribution implements the exact same API, by running an automated test suite which defines the API. 119 | 120 | ![TodoBackend](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/todobackend.png?raw=true) 121 | 122 | There are multiple free implementations available. Some implementations provide endpoints to be tested in `heroku`. [Heroku provide free hosting for a Java application but this is on-demand](https://devcenter.heroku.com/articles/deploying-spring-boot-apps-to-heroku). With `Heroku` The application will be sleeping until you access the endpoint. So it will take 30s for the first person to have the application running. Among the available free endpoints we can list: 123 | - `Endpoint#1` : [https://todo-back-springboot220-java12.herokuapp.com/todos](https://todo-back-springboot220-java12.herokuapp.com/todos) 124 | - `Endpoint#2` : [https://todo-quarkus.herokuapp.com/todos](https://todo-quarkus.herokuapp.com/todos) 125 | - `Endpoint#3` : [https://todo-backend-micronaut.herokuapp.com/todos](https://todo-backend-micronaut.herokuapp.com/todos) 126 | 127 | **✅ Step 2b. Test TodoBackEnd Spec Runner** : Locate the [spec runner](https://www.todobackend.com/specs/index.html) and use one of the `endpoints` listed above to evaluate if API matchs the requirements. To do so copy-paste one URL and click `Run Tests`. 128 | 129 | 130 | ![TodoBackendTest](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/todobackend-runtest.png?raw=true) 131 | 132 | *Sample URL* 133 | ``` 134 | https://www.todobackend.com/specs/index.html?https://todo-back-springboot220-java12.herokuapp.com/todos 135 | ``` 136 | 137 | **👁️ Expected output** 138 | 139 | ![TodoBackendOuput](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/todobackend-output-host.png?raw=true) 140 | 141 | **Note:** *During the live stream you will be hundreds testing the same endpoints so - maybe - we could hit some issues = race conditions.* 142 | 143 | **✅ Step 2c. Test TodoBackEnd Web Client** : todoBackend.com provides a [client](https://www.todobackend.com/client/index.html) to work with the API. As before pick one of the `endpoints` listed before and try the client. 144 | 145 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/todobackend-runclient.png?raw=true) 146 | 147 | **👁️ Expected output** 148 | 149 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/todobackend-output-client.png?raw=true) 150 | 151 | Our mission withing the next hour is to implement the *backend API* and store data into Apache Cassandra™. We have you covered by providing the skeleton of the application. 152 | 153 | **✅ Step 2d. Start Backend API** : By using a maven command or run application in your IDE 154 | 155 | ```bash 156 | # Build the project without tests (you did not implemented them yet TDD baby !) 157 | mvn clean install -Dmaven.test.skip=true 158 | 159 | # Navigate to the proper folder 160 | cd todobackend-cassandra/ 161 | 162 | # Start the backend API 163 | mvn spring-boot:run 164 | ``` 165 | 166 | **👁️ Expected output** 167 | ```bash 168 | [...] 169 | [INFO] Reactor Summary for Spring microservices with Apache Cassandra 1.0-SNAPSHOT: 170 | [INFO] 171 | [INFO] Spring microservices with Apache Cassandra ......... SUCCESS [ 0.004 s] 172 | [INFO] + todobackend-cassandra ............................ SUCCESS [ 0.122 s] 173 | [INFO] ------------------------------------------------------------------------ 174 | [INFO] BUILD SUCCESS 175 | [INFO] ------------------------------------------------------------------------ 176 | ``` 177 | 178 | ```bash 179 | ________ __ __ __ .__ 180 | \______ \ _______ __/ \ / \ | __ _____| |__ ____ ______ 181 | | | \_/ __ \ \/ /\ \/\/ / |/ / / ___/ | \ / _ \\____ \ 182 | | ` \ ___/\ / \ /| < \___ \| Y ( <_> ) |_> > 183 | /_______ /\___ >\_/ \__/\ / |__|_ \/____ >___| /\____/| __/ 184 | \/ \/ \/ \/ \/ \/ |__| 185 | 186 | Backend API implementation of todobackend.com 187 | We are using SpringBoot and Apache Cassandra 188 | The application is started at http://localhost:8080 189 | 190 | 14:54:54.773 INFO com.datastax.sample.TodoBackendApplication : Starting TodoBackendApplication on clunhost with PID 75757 (/Users/cedricklunven/dev/WORKSPACES/DATASTAX/microservices-java-workshop-online/wkshop-microservice-2-spring-boot/target/classes started by cedricklunven in /Users/cedricklunven/dev/WORKSPACES/DATASTAX/microservices-java-workshop-online/wkshop-microservice-2-spring-boot) 191 | 14:54:54.775 INFO com.datastax.sample.TodoBackendApplication : No active profile set, falling back to default profiles: default 192 | 14:55:03.604 INFO com.datastax.sample.TodoBackendApplication : Started TodoBackendApplication in 1.075 seconds (JVM running for 1.492) 193 | ``` 194 | 195 | **✅ Step 2e. Show Api Documentation** : through your browser 196 | 197 | - 💻 If you are on your **laptop** : open a browser and navigate to [http://localhost:8080](http://localhost:8080) 198 | 199 | - ☁️ If you are on **gitpod** : a popup may show up and redirect you to `https://8080-.<>your_region.gitpod.io` as you can see this an alias for port `8080`. 200 | 201 | **👁️ Expected output** 202 | 203 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/backend-doc.png?raw=true) 204 | 205 | **✅ Step 2f. Test Backend API** :using the OpenAPI generated documentation. You can open the `GET` bloc labeled `/api/v1/todos/` and pick `Try It Out`. Then locate `Execute` to test the API and get a few results. 206 | 207 | **Note:** *For some resources `/api/v1/todos/{task-id}` you need to provide a valid UUID as a string. You can get the list of valid ones by invoking the operation `GET /api/v1/todos/` first. The default value `6f6c5b47-4e23-4437-ada8-d0a6f79330a2` should work.* 208 | 209 | **👁️ Expected output** 210 | 211 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/todobackend-swagger-test.png?raw=true) 212 | 213 | **✅ Step 2g. Test our Backend API against the spec runner** : This REST API store data **In memory** but is 100% valid. We can validate by testing the same spec runner as before. 214 | 215 | - 💻 If you are on your **laptop** open a browser and navigate to [https://www.todobackend.com/specs/index.html?http://localhost:8080/api/v1/todos/](https://www.todobackend.com/specs/index.html?http://localhost:8080/api/v1/todos/) 216 | 217 | - ☁️ If you are on **gitpod** : a popup may show up and redirect you to `https://8080-.<>your_region.gitpod.io/api/v1/todos/`. 218 | 219 | **👁️ Expected output** 220 | 221 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/realbackend-test.png?raw=true) 222 | 223 | **✅ Step 2h. Test our Web Client UI against our Backend API** : This is neat, the client and spec runner both work even with URL like `localhost` because this is some `javascript` code executed at client side. 224 | 225 | Back the client UI change the URL to match you backend URL : 226 | 227 | - 💻 If your work locally : [https://www.todobackend.com/client/index.html?http://localhost:8080/api/v1/todos/](https://www.todobackend.com/client/index.html?http://localhost:8080/api/v1/todos/) 228 | 229 | - ☁️ If you are using gitpod `https://www.todobackend.com/client/index.html?https://8080-.-eu01.gitpod.io/api/v1/todos/` 230 | 231 | **👁️ Expected output** 232 | 233 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/backend-ok.png?raw=true) 234 | 235 | *HAHA OK, I changed a little bit the values but now this is working....* 236 | 237 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/welldone.jpg?raw=true) 238 | 239 | [🏠 Back to Table of Content](#table-of-content) 240 | 241 | ## 3. Create your Astra instance 242 | 243 | `ASTRA` service is available at url [https://astra.datastax.com](https://astra.datastax.com/) 244 | 245 | **✅ Step 3a.Register (if needed) and Sign In to Astra** : You can use your `Github`, `Google` accounts or register with an `email` 246 | 247 | - [Registration Page](https://astra.datastax.com/register) 248 | 249 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/astra-create-register.png?raw=true) 250 | 251 | - [Authentication Page](https://astra.datastax.com/) 252 | 253 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/astra-create-login.png?raw=true) 254 | 255 | 256 | **✅ Step 3b. Fill the Create New Database Form** : As you don't have have any instances the login will route through the instance creation form. You will find below which values to enter for each field. 257 | 258 | - *Initialization Form* 259 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/astra-create-2.png?raw=true) 260 | 261 | 262 | - **Set the Compute Size**: For the work we are doing please use `Free tier`. You instance will be there forever, free of charge. If you already have a free tier db that you created in a previous workshop (`killrvideo`) you can reuse it. 263 | 264 | - **Select region**: This is the region where your database will reside physically (choose one close to you or your users). For people in EMEA please use `europe-west-1` idea here is to reduce latency. 265 | 266 | - **Fill in the database name** - Proposed value `dev-workshop-db`. You can use any alphanumeric value it is not part of the connection fields. Now it will be part of a file downloaded later and you should avoid capital letters. 267 | 268 | With the 3 fields below you can pick any name, simply REMIND them, they will be required both to connect and do the exercises. 269 | 270 | - **Fill in the keyspace name** - Proposed value `todoapp` (no spaces, alpha numeric) 271 | 272 | - **Fill in the user name** - `todouser`. Note the user name is case-sensitive. Please use the case we suggest here. 273 | 274 | - **Fill in the user password** - `todopassword`. Fill in both the password and the confirmation fields. Note that the password is also case-sensitive. Please use the case we suggest here. 275 | 276 | - **Launch the database**. Review all the fields to make sure they are as shown, and click the Launch Database button. 277 | 278 | **👁️ Expected output** 279 | 280 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/astra-create-3.png?raw=true) 281 | 282 | **✅ Step 3c. View your Database and connect** : View your database. It may take 2-3 minutes for your database to spin up. You will receive an email at that point. But, go ahead and continue with the rest of the exercise now. 283 | 284 | **👁️ Expected output** 285 | 286 | *Initializing* 287 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/astra-create-4.png?raw=true) 288 | 289 | *Database is ready* 290 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/astra-create-5.png?raw=true) 291 | 292 | **✅ Step 3d. Open DataStax Studio** : Locate `Launch Developer Studio` on the bottom left part of the screen and click on `Launch now`. Please enter the same credentials you used for instance creation. 293 | 294 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/launch-studio.png?raw=true) 295 | 296 | - **Fill in the Database User name** - `todouser`. Note the user name is case-sensitive. Please use the case we suggest here. 297 | 298 | - **Fill in the password** - `todopassword`. Fill in both the password and the confirmation fields. Note that the password is also case-sensitive. Please use the case we suggest here. 299 | 300 | **👁️ Expected output** 301 | 302 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/astra-create-6.png?raw=true) 303 | 304 | > **⚠️ Important** 305 | > ``` 306 | > The instructor will show you on screen how to create a token 307 | > but will have to destroy to token immediately for security reasons. 308 | > ``` 309 | 310 | **✅ Step 3e. Import a notebook** : DataStax studio should now be opened. 311 | 312 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/launch-studio-home.png?raw=true) 313 | 314 | - Download locally the file `datastax-studio-notebook.tar` located in `z-materials/notebooks/datastax-studio-notebook.tar` [here](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/notebooks/datastax-studio-notebook.tar?raw=true) 315 | 316 | - Import the file in studio with a drag and drop in the Datastax studio window 317 | 318 | *Importing* 319 | 320 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/launch-studio-import.png?raw=true) 321 | 322 | *File is now opened* 323 | 324 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/launch-studio-open.png?raw=true) 325 | 326 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/welldone.jpg?raw=true) 327 | 328 | 329 | [🏠 Back to Table of Content](#table-of-content) 330 | 331 | 332 | ## 4. Connectivity to Astra 333 | 334 | With our `Cassandra-as-a-service` instance ready let's connect from our application. 335 | 336 | **✅ Step 4a. Download the secure connect bundle** : Go to home page. Process to a `refresh` (F5) of the page (the download link will be valid 5 min we want to be sure we don't reach the timeout). Locate link `Download secure connect bundle` and click. You should download a file named `secure-connect-.zip`. Please remind the location of the file. 337 | 338 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/astra-create-7.png?raw=true) 339 | 340 | Save the file in a path you will remind, again we will need it for the next exercises. 341 | 342 | **✅ Step 4b. Upload the zip in `gitpod`** : If you are working with gitpod the `secure connect bundle` needs to be uploaded there. 343 | 344 | - Select the root folder, name of the project and go to `File > Upload Files...`, locate the `zip` and import. *(in our tests the menu `File>Upload` Files only when a folder is selected).* 345 | 346 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/gitpod-upload-files.png?raw=true) 347 | 348 | - You can now see the file in the resources tree 349 | 350 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/gitpod-updated.png?raw=true) 351 | 352 | The file path is located at `/workspace/microservices-java-workshop-online/secure-connect-dev-workshop-db.zip` (because my db name is `dev-workshop-db`). 353 | 354 | 355 | **✅ Step 4c. Fix unit test `ConnectivityToAstraExplicitTest.java`** 356 | 357 | - Unit Tests are located in `src/test/java` [HERE](./todobackend-cassandra/src/test/java/com/datastax/samples/astra). Open the file `ConnectivityToAstraExplicitTest` and fill the properties with your Astra informations. 358 | 359 | *Do not copy-paste - this is a sample for me.* 360 | ```java 361 | public static String ASTRA_ZIP_FILE = "/Users/cedricklunven/Downloads/secure-connect-dev-workshop-db.zip"; 362 | public static String ASTRA_USERNAME = "todouser"; 363 | public static String ASTRA_PASSWORD = "todopassword"; 364 | public static String ASTRA_KEYSPACE = "todoapp"; 365 | ``` 366 | 367 | ``` 368 | ⚠️ By default Autosaved is not enabled in Gitpod. Don't forget to save your modifications with CTRL+S 369 | ``` 370 | 371 | - You can now run the UNIT TEST with your IDE or Maven in a terminal (easier with gitpod 372 | ```bash 373 | mvn test -Dtest=com.datastax.samples.astra.ConnectivityToAstraExplicitTest#should_connect_to_Astra_static 374 | ``` 375 | 376 | **👁️ Expected output** 377 | 378 | ```bash 379 | ConnectivityToAstraExplicitTest: + [OK] - Connection Established to Astra with Keyspace todoapp 380 | ``` 381 | 382 | **✅ Step 4d. Fix unit test `ConnectivityToAstraWithConfTest.java`** 383 | 384 | Providing the parameter in static way is useful for tests but we can do better but externalizing to a configuration file in `src/test/resources`: **`application_test.conf`** Open the file and edit with your Astra informations. 385 | 386 | *Do not copy-paste* 387 | ```yaml 388 | datastax-java-driver { 389 | basic { 390 | request { 391 | timeout = 5 seconds 392 | consistency = LOCAL_QUORUM 393 | page-size = 5000 394 | } 395 | session-keyspace = todoapp 396 | cloud { 397 | secure-connect-bundle = /workspace/microservices-java-workshop-online/secure-connect-dev-workshop-db.zip 398 | } 399 | } 400 | advanced { 401 | auth-provider { 402 | class = PlainTextAuthProvider 403 | username = todouser 404 | password = todopassword 405 | } 406 | } 407 | } 408 | ``` 409 | 410 | ``` 411 | ⚠️ By default Autosaved is not enabled in Gitpod. Don't forget to save your modifications with CTRL+S 412 | ``` 413 | 414 | - You can now run the UNIT TEST with your IDE or Maven in a terminal (easier with gitpod) 415 | 416 | ```bash 417 | mvn test -Dtest=com.datastax.samples.astra.ConnectivityToAstraWithConfTest#should_connect_to_Astra_withConfig 418 | ``` 419 | 420 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/welldone.jpg?raw=true) 421 | 422 | [🏠back to table of content](#table-of-content) 423 | 424 | ## 5. CRUD Repository 425 | 426 | It is now time to define the data model in Apache Cassandra. With the explanations coming from the slides you know this is the table we are looking for : 427 | 428 | ```sql 429 | CREATE TABLE todoapp.todo_tasks ( 430 | uid uuid PRIMARY KEY, 431 | completed boolean, 432 | offset int, 433 | title text 434 | ); 435 | ``` 436 | 437 | **✅ Step 5a. Run test `CreateSchemaInAstraTest`** : There are multiple ways to create the table : `DataStax Studio`, `CQL Console` in Astra or even any `Cqlsh` instance with the proper conf file. We will go the Java way with an Integration test. You don't have to code here the test will reuse the same file. Locate [CreateSchemaInAstraTest](./todobackend-cassandra/src/test/java/com/datastax/samples/astra/CreateSchemaInAstraTest.java) browse the code before executing: 438 | 439 | - Run the test 440 | 441 | ```bash 442 | mvn test -Dtest=com.datastax.samples.astra.CreateSchemaInAstraTest#should_create_expected_table 443 | ``` 444 | 445 | **👁️ Expected output** 446 | 447 | ```bash 448 | CreateSchemaInAstraTest: Connection Established to Astra with Keyspace 'todoapp' 449 | CreateSchemaInAstraTest: Table 'todo_tasks' has been created (if needed). 450 | ``` 451 | 452 | **✅ Step 5b. Check that table `todoapp.todo_tasks` now exist**: You can go back to Astra in the notebook we have imported or the `CqlConsole` and execute. This is the reason we made you import the noteboolk it is 453 | quite visual and you can execute some `CQL` commands easily. 454 | 455 | ```sql 456 | describe keyspace todoapp 457 | ``` 458 | 459 | **👁️ Expected output STUDIO** 460 | 461 | - Locate the notebook 462 | 463 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/locate-studio.png?raw=true) 464 | 465 | - Execute the command 466 | 467 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/describe-output-studio.png?raw=true) 468 | 469 | **👁️ Expected output CQLCONSOLE** 470 | 471 | - Locate the console 472 | 473 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/locate-cqlconsole.png?raw=true) 474 | 475 | - Execute the command 476 | 477 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/describe-output-cqlconsole.png?raw=true) 478 | 479 | **✅ Step 5c. Fix Unit Test `CrudWithCassandraDriverIntegrationTest`:** We will insert values into the table and extract values from it. 480 | 481 | Locate [CrudWithCassandraDriverIntegrationTest](./todobackend-cassandra/src/test/java/com/datastax/samples/astra/CrudWithCassandraDriverIntegrationTest.java#L66) class and specially method `test_Insert()`. Fix the test and execute it with the following commands. 482 | 483 | - Execute your test (solution is provided at the bottom of the class) 484 | 485 | ```bash 486 | mvn test -Dtest=com.datastax.samples.astra.CrudWithCassandraDriverIntegrationTest#test_Insert 487 | ``` 488 | 489 | *Here is the solution* 490 | ```java 491 | SimpleStatement stmtInsertTask = SimpleStatement.builder("" 492 | + "INSERT INTO todo_tasks(uid, title, offset, completed)" 493 | + "VALUES (?, ?, ?, ?)") 494 | .addPositionalValue(sampleUID) 495 | .addPositionalValue(sampleTitle) 496 | .addPositionalValue(sampleOrder) 497 | .addPositionalValue(sampleComplete) 498 | .build(); 499 | cqlSession.execute(stmtInsertTask); 500 | ``` 501 | 502 | ``` 503 | ⚠️ By default Autosaved is not enabled in Gitpod. Don't forget to save your modifications with CTRL+S 504 | ``` 505 | 506 | - There is another test in the same class to test all CRUD operations you can test: 507 | 508 | ```bash 509 | mvn test -Dtest=com.datastax.samples.astra.CrudWithCassandraDriverIntegrationTest#should_create_task_with_new_uid 510 | ``` 511 | 512 | **✅ Step 5d. Create bean `CqlSession` in the application**: 513 | 514 | - Locate the file `CassandraDriverConfig` [here](./todobackend-cassandra/src/main/java/com/datastax/sample/conf/CassandraDriverConfig.java) and uncomment the annotation `@Configuration`. As you can see we delegate the configuration to a file. If we don't provide a `DriverConfigLoader` it will use `application.conf` 515 | 516 | - Copy-paste the content of file `src/test/resources/application_test.conf` to `src/main/resources/application.conf` 517 | 518 | ```bash 519 | cp todobackend-cassandra/src/test/resources/application_test.conf todobackend-cassandra/src/main//resources/application.conf 520 | ``` 521 | 522 | ``` 523 | ⚠️ By default Autosaved is not enabled in Gitpod. Don't forget to save your modifications with CTRL+S 524 | ``` 525 | 526 | **✅ Step 5e. Change injection dependency in `TodoListRestController`** 527 | 528 | - [`TodoListRepository`](./todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepository.java) is an interface to design the CRUD operations for tasks. Locate the controller [`TodoListRestController`](./todobackend-cassandra/src/main/java/com/datastax/sample/resources/TodoListRestController.java). 529 | 530 | - As you can see we are specifically picking `todobackend.repo.inmemory`. Change it to `todobackend.repo.cassandra-driver` by commenting/uncommenting proper lines. 531 | 532 | **👁️ Expected code ** 533 | 534 | ```java 535 | @Autowired 536 | //@Qualifier("todobackend.repo.inmemory") 537 | @Qualifier("todobackend.repo.cassandra-driver") 538 | // @Qualifier("todobackend.repo.cassandra-object-mapper") 539 | // @Qualifier("todobackend.repo.spring-data-cassandra") 540 | private TodoListRepository todoRepository; 541 | ``` 542 | 543 | Now we now how we will switch from one implementation to another. Take a look at class [`TodoListRepositoryCassandraDriverImpl`](./todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepositoryCassandraDriverImpl.java) implementing the `TodoListRepository` to see how we proceed. 544 | 545 | **✅ Step 5f. Restart the application**: Use the `CTRL+C` shortcut on the terminal window to stop running the application and restart. 546 | 547 | **✅ Step 5g. Test the application connected to ASTRA.** we wills now reuse the provided client to work with our backend API now connected to ASTRA !. 548 | 549 | - 💻 If your work locally : [https://www.todobackend.com/client/index.html?http://localhost:8080/api/v1/todos/](https://www.todobackend.com/client/index.html?http://localhost:8080/api/v1/todos/) 550 | 551 | 552 | - ☁️ If you are using gitpod `https://www.todobackend.com/client/index.html?https://8080-.-eu01.gitpod.io/api/v1/todos/` 553 | 554 | 555 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/welldone.jpg?raw=true) 556 | 557 | [🏠back to table of content](#table-of-content) 558 | 559 | ## 6. CRUD Repository with Object Mapper 560 | 561 | **✅ Step 6a. Check that the `ObjectMapper` repository is working** : We test want to test class [`CrudWithObjectMapperTest`](./todobackend-cassandra/src/test/java/com/datastax/samples/astra/CrudWithObjectMapperTest.java). 562 | 563 | ```bash 564 | mvn test -Dtest=com.datastax.samples.astra.CrudWithObjectMapperTest 565 | ``` 566 | 567 | **✅ Step 6b. Change injection dependency in `TodoListRestController`**: We switch from one implementation to another. Take a look at class [`TodoListRepositoryObjectMapperImpl`](./todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepositoryObjectMapperImpl.java) implementing the `TodoListRepository` to see how we proceed. 568 | 569 | - In controller [`TodoListRestController`](./todobackend-cassandra/src/main/java/com/datastax/sample/resources/TodoListRestController.java) change from `@Qualifier("todobackend.repo.cassandra-driver")` to `@Qualifier("todobackend.repo.cassandra-object-mapper")` by commenting/uncommenting proper lines. 570 | 571 | **👁️ Expected code ** 572 | 573 | ```java 574 | @Autowired 575 | //@Qualifier("todobackend.repo.inmemory") 576 | //@Qualifier("todobackend.repo.cassandra-driver") 577 | @Qualifier("todobackend.repo.cassandra-object-mapper") 578 | // @Qualifier("todobackend.repo.spring-data-cassandra") 579 | private TodoListRepository todoRepository; 580 | ``` 581 | 582 | **✅ Step 6b. Restart the application**: Use the `CTRL+C` shortcut on the terminal window to stop running the application and restart. 583 | 584 | **✅ Step 6c. Test the application connected to ASTRA.** we wil now reuse the provided clientto work with our backend API now connected to ASTRA !. 585 | 586 | - 💻 If your work locally : [https://www.todobackend.com/client/index.html?http://localhost:8080/api/v1/todos/](https://www.todobackend.com/client/index.html?http://localhost:8080/api/v1/todos/) 587 | 588 | - ☁️ If you are using gitpod `https://www.todobackend.com/client/index.html?https://8080-.-eu01.gitpod.io/api/v1/todos/` 589 | 590 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/welldone.jpg?raw=true) 591 | 592 | [🏠back to table of content](#table-of-content) 593 | 594 | ## 7. CRUD Repository with Spring Data 595 | 596 | Spring-Data is like `ObjectMapper` and help reducing boilerplate code. You define entities and interfaces, the code under the hood is generated for you. 597 | 598 | **✅ 7.a Add Spring Data Dependency**: In the `pom.xml` file of project `todobackend-cassandra` uncomment Spring Data dependency. 599 | 600 | ```xml 601 | 602 | org.springframework.boot 603 | spring-boot-starter-data-cassandra 604 | 605 | ``` 606 | 607 | **Note** *As soon as the library is imported it will look for a bean `CqlSession` and if nothing existing it will try to connect to localhost. As the workshop started with the store InMemory we decided to comment this at beginning at the workshop.* 608 | 609 | Now we now how we will switch from one implementation to another. Take a look at class [`TodoListRepositorySpringDataImpl`](./todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepositorySpringDataImpl.java) implementing the `TodoListRepository` to see how we proceed. 610 | 611 | **✅ 7.b Uncomment all the source code we will need**: With the new dependency we can now uncomment part of the code working with Spring-Data. 612 | 613 | - Uncomment code in class [`TaskSpringData`](./todobackend-cassandra/src/main/java/com/datastax/sample/springdata/TaskSpringData.java) 614 | 615 | ```java 616 | // Uncomment Imports 617 | import org.springframework.data.cassandra.core.cql.PrimaryKeyType; 618 | import org.springframework.data.cassandra.core.mapping.CassandraType; 619 | import org.springframework.data.cassandra.core.mapping.CassandraType.Name; 620 | import org.springframework.data.cassandra.core.mapping.Column; 621 | import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; 622 | import org.springframework.data.cassandra.core.mapping.Table; 623 | 624 | [...] 625 | 626 | // Uncomment annotations 627 | @Table(value = TodoAppSchema.TABLE_TODO_TASKS) 628 | 629 | [...] 630 | @PrimaryKeyColumn( 631 | name = TodoAppSchema.TASK_COL_UID, ordinal = 0, 632 | type = PrimaryKeyType.PARTITIONED) 633 | @CassandraType(type = Name.UUID) 634 | private UUID uuid; 635 | 636 | [...] 637 | ``` 638 | - Uncomment code in class [`TaskSpringDataRepository`](./todobackend-cassandra/src/main/java/com/datastax/sample/springdata/TaskSpringDataRepository.java) 639 | 640 | ```java 641 | // Uncomment Imports 642 | import org.springframework.data.cassandra.repository.CassandraRepository; 643 | import org.springframework.data.cassandra.repository.Query; 644 | 645 | [...] 646 | 647 | // Uncomment bloc 648 | @Repository("todobackend.repo.spring") 649 | public interface TaskSpringDataRepository extends TodoAppSchema, CassandraRepository { 650 | 651 | @Query("SELECT * FROM " + TodoAppSchema.TABLE_TODO_TASKS + 652 | " WHERE " + TodoAppSchema.TASK_COL_UID + " = ?0") 653 | Optional findByTaskByIdO(UUID taskid); 654 | } 655 | 656 | ``` 657 | 658 | - Uncomment code in class [`TodoListRepositorySpringDataImpl`](./todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepositorySpringDataImpl.java) 659 | 660 | ```java 661 | import com.datastax.sample.springdata.TaskSpringDataRepository; 662 | 663 | // Uncomment bloc 664 | @Repository("todobackend.repo.spring-data-cassandra") 665 | public class TodoListRepositorySpringDataImpl implements TodoListRepository { 666 | 667 | private TaskSpringDataRepository taskDao; 668 | 669 | public TodoListRepositorySpringDataImpl(TaskSpringDataRepository taskDao) { 670 | this.taskDao = taskDao; 671 | } 672 | 673 | @Override 674 | public List findAll() { 675 | return taskDao.findAll().stream() 676 | .map(TaskSpringData::mapAsTask) 677 | .collect(Collectors.toList()); 678 | } 679 | 680 | @Override 681 | public void deleteAll() { 682 | taskDao.deleteAll(); 683 | } 684 | 685 | @Override 686 | public Optional findById(UUID uid) { 687 | if (null == uid) return Optional.empty(); 688 | Optional entity = taskDao.findById(uid); 689 | if (entity.isEmpty()) return Optional.empty(); 690 | return Optional.ofNullable(entity.get().mapAsTask()); 691 | } 692 | 693 | @Override 694 | public void upsert(Task dto) { 695 | if (null != dto) { 696 | taskDao.save(new TaskSpringData(dto)); 697 | } 698 | } 699 | 700 | @Override 701 | public void delete(UUID uid) { 702 | TaskSpringData tsd = new TaskSpringData(); 703 | tsd.setUuid(uid); 704 | taskDao.delete(tsd); 705 | } 706 | } 707 | ``` 708 | 709 | **✅ Step 7c. Change injection dependency in `TodoListRestController`**: We have create other implementations for you this time using Spring Data. 710 | 711 | - In controller [`TodoListRestController`](./todobackend-cassandra/src/main/java/com/datastax/sample/resources/TodoListRestController.java) nowChange `@Qualifier` to `todobackend.repo.spring-data-cassandra` by commenting/uncommenting proper lines. 712 | 713 | **👁️ Expected code**: 714 | 715 | ```java 716 | @Autowired 717 | //@Qualifier("todobackend.repo.inmemory") 718 | //@Qualifier("todobackend.repo.cassandra-driver") 719 | //@Qualifier("todobackend.repo.cassandra-object-mapper") 720 | @Qualifier("todobackend.repo.spring-data-cassandra") 721 | private TodoListRepository todoRepository; 722 | ``` 723 | 724 | **✅ Step 7d. Restart the application**: Use the `CTRL+C` shortcut on the terminal window to stop running the application and restart. 725 | 726 | **✅ Step 7e. Test the application connected to ASTRA.** we wil now reuse the provided clientto work with our backend API now connected to ASTRA !. 727 | 728 | - 💻 If your work locally : [https://www.todobackend.com/client/index.html?http://localhost:8080/api/v1/todos/](https://www.todobackend.com/client/index.html?http://localhost:8080/api/v1/todos/) 729 | 730 | - ☁️ If you are using gitpod `https://www.todobackend.com/client/index.html?https://8080-.-eu01.gitpod.io/api/v1/todos/` 731 | 732 | ![TodoBackendClient](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/welldone.jpg?raw=true) 733 | 734 | [🏠back to table of content](#table-of-content) 735 | 736 | THE END. 737 | 738 | 739 | 740 | 741 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | com.datastax.examples 7 | todobackend-cassandra-parent 8 | 1.0-SNAPSHOT 9 | 10 | Spring microservices with Apache Cassandra 11 | pom 12 | 2020 13 | 14 | This project contains Spring microservices that use Apache Cassandra as the database. 15 | One uses Spring Data Cassandra for data access and the other uses Spring Boot and the 16 | Cassandra Java driver version 4.x directly. 17 | 18 | 19 | 20 | 21 | 22 | 11 23 | 3.8.1 24 | 1.4.13 25 | 26 | 27 | 5.2.6.RELEASE 28 | 2.3.0.RELEASE 29 | 2.2.3.RELEASE 30 | 3.0.0.RELEASE 31 | 3.3.0.RELEASE 32 | 33 | 4.6.1 34 | 35 | 36 | 1.3.3 37 | 1.2.3 38 | 2.11.0 39 | 1.3.9 40 | 2.9.2 41 | 3.26.0 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-parent 48 | 2.3.0.RELEASE 49 | 50 | 51 | 52 | 53 | todobackend-cassandra 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | org.springframework 62 | spring-aop 63 | ${spring.version} 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-actuator 68 | ${spring-boot.version} 69 | 70 | 71 | org.springframework.boot 72 | spring-boot-starter-web 73 | ${spring-boot.version} 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-starter-data-rest 78 | ${spring-boot.version} 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-starter-data-cassandra 83 | ${spring-boot.version} 84 | 85 | 86 | org.springframework.boot 87 | spring-boot-devtools 88 | ${spring-boot.version} 89 | 90 | 91 | org.springframework.data 92 | spring-data-rest-core 93 | ${spring-data-rest.version} 94 | 95 | 96 | 97 | 98 | com.datastax.oss 99 | java-driver-core 100 | ${cassandra-java-driver.version} 101 | 102 | 103 | com.datastax.oss 104 | java-driver-query-builder 105 | ${cassandra-java-driver.version} 106 | 107 | 108 | com.datastax.oss 109 | java-driver-mapper-runtime 110 | ${cassandra-java-driver.version} 111 | 112 | 113 | com.datastax.oss 114 | java-driver-mapper-processor 115 | ${cassandra-java-driver.version} 116 | 117 | 118 | 119 | 120 | commons-fileupload 121 | commons-fileupload 122 | ${common-fileupload} 123 | 124 | 125 | ch.qos.logback 126 | logback-classic 127 | ${logback.version} 128 | 129 | 130 | com.fasterxml.jackson.core 131 | jackson-core 132 | ${jackson.version} 133 | 134 | 135 | 136 | 137 | org.springdoc 138 | springdoc-openapi-ui 139 | ${springdoc.version} 140 | 141 | 142 | org.springdoc 143 | springdoc-openapi-data-rest 144 | ${springdoc.version} 145 | 146 | 147 | 148 | 149 | io.springfox 150 | springfox-swagger2 151 | ${swagger.version} 152 | 153 | 154 | io.springfox 155 | springfox-swagger-ui 156 | ${swaggerui.version} 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | org.apache.maven.plugins 167 | maven-compiler-plugin 168 | ${maven-plugin-compiler.version} 169 | 170 | 171 | com.spotify 172 | dockerfile-maven-plugin 173 | ${maven-plugin-dockerfile.version} 174 | 175 | datastax-samples/${project.artifactId} 176 | ${project.version} 177 | 178 | target/${project.build.finalName}.jar 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | DataStax 188 | http://datastax.com 189 | 190 | 191 | -------------------------------------------------------------------------------- /todobackend-cassandra/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | todobackend-cassandra 8 | jar 9 | + todobackend-cassandra 10 | 11 | 12 | com.datastax.examples 13 | todobackend-cassandra-parent 14 | 1.0-SNAPSHOT 15 | ../pom.xml 16 | 17 | 18 | 19 | 20 | 21 | 22 | com.datastax.oss 23 | java-driver-core 24 | 25 | 26 | com.datastax.oss 27 | java-driver-query-builder 28 | 29 | 30 | com.datastax.oss 31 | java-driver-mapper-runtime 32 | 33 | 34 | 35 | 36 | ch.qos.logback 37 | logback-classic 38 | 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-web 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-actuator 48 | 49 | 50 | 56 | 57 | 58 | 59 | org.springdoc 60 | springdoc-openapi-ui 61 | 62 | 63 | 64 | 65 | org.springframework.boot 66 | spring-boot-devtools 67 | true 68 | 69 | 70 | 71 | 72 | org.junit.jupiter 73 | junit-jupiter-api 74 | test 75 | 76 | 77 | org.junit.jupiter 78 | junit-jupiter-engine 79 | test 80 | 81 | 82 | org.junit.platform 83 | junit-platform-runner 84 | test 85 | 86 | 87 | org.springframework.boot 88 | spring-boot-starter-test 89 | test 90 | 91 | 92 | com.vaadin.external.google 93 | android-json 94 | 95 | 96 | junit 97 | junit 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | org.apache.maven.plugins 108 | maven-surefire-plugin 109 | 110 | 111 | org.apache.maven.plugins 112 | maven-compiler-plugin 113 | 114 | ${java.version} 115 | ${java.version} 116 | ${java.version} 117 | false 118 | 119 | 120 | com.datastax.oss 121 | java-driver-mapper-processor 122 | ${cassandra-java-driver.version} 123 | 124 | 125 | 126 | 127 | 128 | org.springframework.boot 129 | spring-boot-maven-plugin 130 | 131 | 132 | 133 | repackage 134 | 135 | 136 | 137 | 138 | 139 | com.spotify 140 | dockerfile-maven-plugin 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/TodoBackendApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 4 | * the License. You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 9 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | * specific language governing permissions and limitations under the License. 11 | * 12 | * Copyright 2013-2016 the original author or authors. 13 | */ 14 | package com.datastax.sample; 15 | 16 | import org.springframework.boot.SpringApplication; 17 | import org.springframework.boot.autoconfigure.SpringBootApplication; 18 | 19 | /** 20 | * Spring boot application. 21 | * 22 | * @author Cedrick LUNVEN (@clunven) 23 | */ 24 | @SpringBootApplication 25 | public class TodoBackendApplication { 26 | 27 | /** Main method to the demo. */ 28 | public static void main(String[] args) { 29 | SpringApplication.run(TodoBackendApplication.class, args); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/conf/CassandraDriverConfig.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.conf; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | import com.datastax.oss.driver.api.core.CqlSession; 7 | 8 | /** 9 | * Configuration of connectivity with Cassandra. 10 | */ 11 | //@Configuration 12 | public class CassandraDriverConfig { 13 | 14 | @Bean 15 | public CqlSession cqlSession() { 16 | return CqlSession.builder().build(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/conf/OpenApiDocumentationConfig.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.conf; 2 | 3 | import org.springdoc.core.GroupedOpenApi; 4 | import org.springframework.beans.factory.annotation.Value; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import io.swagger.v3.oas.models.OpenAPI; 9 | import io.swagger.v3.oas.models.info.Info; 10 | import io.swagger.v3.oas.models.info.License; 11 | import io.swagger.v3.oas.models.servers.Server; 12 | 13 | @Configuration 14 | public class OpenApiDocumentationConfig { 15 | 16 | @Bean 17 | public OpenAPI openApiSpec(@Value("${springdoc.version}") String appVersion) { 18 | String des = "Implementation of TodoBackend application with Spring WebMVC and storage in Apache Cassandra"; 19 | Info info = new Info().title("DevWorkshop :: TodoBackend Rest API") 20 | .version(appVersion).description(des) 21 | .termsOfService("http://swagger.io/terms/") 22 | .license(new License().name("Apache 2.0") 23 | .url("http://springdoc.org")); 24 | return new OpenAPI().addServersItem(new Server().url("/")).info(info); 25 | } 26 | 27 | @Bean 28 | public GroupedOpenApi actuatorApi() { 29 | return GroupedOpenApi.builder().setGroup("Monitoring (Actuator)") 30 | .pathsToMatch("/actuator/**") 31 | .pathsToExclude("/actuator/health/*") 32 | .build(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/conf/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.conf; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 5 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | 8 | /** 9 | * Add a CORS Filter to allow cross-origin 10 | * 11 | * @author Cedrick LUNVEN (@clunven) 12 | */ 13 | @Configuration 14 | public class WebConfig implements WebMvcConfigurer { 15 | 16 | /** 17 | * By overriding `addCorsMappings` from {@link WebMvcConfigurer}, 18 | * we allow access with the full JavaScript Access. 19 | * 20 | * {@inheritDoc} 21 | */ 22 | @Override 23 | public void addCorsMappings(CorsRegistry registry) { 24 | registry.addMapping("/**"); 25 | } 26 | 27 | /** 28 | * By overriding `addResourceHandlers` from {@link WebMvcConfigurer}, 29 | * we tell SpringMVC not to use Thymeleaf to access Swagger UI 30 | * 31 | * {@inheritDoc} 32 | */ 33 | @Override 34 | public void addResourceHandlers(final ResourceHandlerRegistry registry) { 35 | registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); 36 | registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/model/Task.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.UUID; 5 | 6 | /** 7 | * Object to be exposed in the REST API. 8 | * 9 | * @author Cedrick LUNVEN (@clunven) 10 | */ 11 | public class Task implements Serializable, Comparable { 12 | 13 | /** Serial. */ 14 | private static final long serialVersionUID = -7930662827102682933L; 15 | 16 | /** Unique id for the task. */ 17 | private UUID uuid; 18 | 19 | /** Title. */ 20 | private String title; 21 | 22 | /** Status. */ 23 | private boolean completed = false; 24 | 25 | /** order field. */ 26 | private int order = 0; 27 | 28 | /** 29 | * Constructors. 30 | */ 31 | public Task() {} 32 | 33 | /** 34 | * Constructor helping for tests 35 | */ 36 | public Task(String title) { 37 | this(UUID.randomUUID(), title, false, -1); 38 | } 39 | 40 | /** 41 | * Full constructor. 42 | */ 43 | public Task(UUID uuid, String title, boolean completed, int order) { 44 | super(); 45 | this.uuid = uuid; 46 | this.title = title; 47 | this.completed = completed; 48 | this.order = order; 49 | } 50 | 51 | /** {@inheritDoc} */ 52 | @Override 53 | public int compareTo(Task other) { 54 | if (other == null) return 1; 55 | return order - other.getOrder(); 56 | } 57 | /** 58 | * Getter accessor for attribute 'uuid'. 59 | * 60 | * @return 61 | * current value of 'uuid' 62 | */ 63 | public UUID getUuid() { 64 | return uuid; 65 | } 66 | 67 | /** 68 | * Setter accessor for attribute 'uuid'. 69 | * @param uuid 70 | * new value for 'uuid ' 71 | */ 72 | public void setUuid(UUID uuid) { 73 | this.uuid = uuid; 74 | } 75 | 76 | /** 77 | * Getter accessor for attribute 'title'. 78 | * 79 | * @return 80 | * current value of 'title' 81 | */ 82 | public String getTitle() { 83 | return title; 84 | } 85 | 86 | /** 87 | * Setter accessor for attribute 'title'. 88 | * @param title 89 | * new value for 'title ' 90 | */ 91 | public void setTitle(String title) { 92 | this.title = title; 93 | } 94 | 95 | /** 96 | * Getter accessor for attribute 'completed'. 97 | * 98 | * @return 99 | * current value of 'completed' 100 | */ 101 | public boolean isCompleted() { 102 | return completed; 103 | } 104 | 105 | /** 106 | * Setter accessor for attribute 'completed'. 107 | * @param completed 108 | * new value for 'completed ' 109 | */ 110 | public void setCompleted(boolean completed) { 111 | this.completed = completed; 112 | } 113 | 114 | /** 115 | * Getter accessor for attribute 'order'. 116 | * 117 | * @return 118 | * current value of 'order' 119 | */ 120 | public int getOrder() { 121 | return order; 122 | } 123 | 124 | /** 125 | * Setter accessor for attribute 'order'. 126 | * @param order 127 | * new value for 'order ' 128 | */ 129 | public void setOrder(int order) { 130 | this.order = order; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/model/TaskBody.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class TaskBody implements Serializable { 6 | 7 | /** Serial. */ 8 | private static final long serialVersionUID = -7930662827102682933L; 9 | 10 | /** Title. */ 11 | private String title; 12 | 13 | /** Status. */ 14 | private boolean completed = false; 15 | 16 | /** order field. */ 17 | private int order = -1; 18 | 19 | /** 20 | * Default constructor 21 | */ 22 | public TaskBody() { 23 | } 24 | 25 | /** 26 | * Getter accessor for attribute 'title'. 27 | * 28 | * @return 29 | * current value of 'title' 30 | */ 31 | public String getTitle() { 32 | return title; 33 | } 34 | 35 | /** 36 | * Setter accessor for attribute 'title'. 37 | * @param title 38 | * new value for 'title ' 39 | */ 40 | public void setTitle(String title) { 41 | this.title = title; 42 | } 43 | 44 | /** 45 | * Getter accessor for attribute 'completed'. 46 | * 47 | * @return 48 | * current value of 'completed' 49 | */ 50 | public boolean isCompleted() { 51 | return completed; 52 | } 53 | 54 | /** 55 | * Setter accessor for attribute 'completed'. 56 | * @param completed 57 | * new value for 'completed ' 58 | */ 59 | public void setCompleted(boolean completed) { 60 | this.completed = completed; 61 | } 62 | 63 | /** 64 | * Getter accessor for attribute 'order'. 65 | * 66 | * @return 67 | * current value of 'order' 68 | */ 69 | public int getOrder() { 70 | return order; 71 | } 72 | 73 | /** 74 | * Setter accessor for attribute 'order'. 75 | * @param order 76 | * new value for 'order ' 77 | */ 78 | public void setOrder(int order) { 79 | this.order = order; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/model/TaskResource.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.UUID; 5 | 6 | /** 7 | * Object to be exposed in the REST API. 8 | * 9 | * @author Cedrick LUNVEN (@clunven) 10 | */ 11 | public class TaskResource implements Serializable { 12 | 13 | /** Serial. */ 14 | private static final long serialVersionUID = -7930662827102682933L; 15 | 16 | /** Hate Oas logic. */ 17 | private String url; 18 | 19 | /** Unique id for the task. */ 20 | private UUID uuid; 21 | 22 | /** Title. */ 23 | private String title; 24 | 25 | /** Status. */ 26 | private boolean completed = false; 27 | 28 | /** order field. */ 29 | private int order = 0; 30 | 31 | /** 32 | * Default constructor. 33 | */ 34 | public TaskResource() {} 35 | 36 | /** 37 | * Create from the dto and target URL. 38 | * 39 | * @param requestURL 40 | * current URL for the request 41 | * @param dto 42 | * dto from DB 43 | */ 44 | public TaskResource(String url, Task dto) { 45 | if (null != dto) { 46 | this.url = url; 47 | this.uuid = dto.getUuid(); 48 | this.title = dto.getTitle(); 49 | this.completed = dto.isCompleted(); 50 | this.order = dto.getOrder(); 51 | } 52 | } 53 | 54 | /** 55 | * Getter accessor for attribute 'url'. 56 | * 57 | * @return 58 | * current value of 'url' 59 | */ 60 | public String getUrl() { 61 | return url; 62 | } 63 | 64 | /** 65 | * Setter accessor for attribute 'url'. 66 | * @param url 67 | * new value for 'url ' 68 | */ 69 | public void setUrl(String url) { 70 | this.url = url; 71 | } 72 | 73 | /** 74 | * Getter accessor for attribute 'uuid'. 75 | * 76 | * @return 77 | * current value of 'uuid' 78 | */ 79 | public UUID getUuid() { 80 | return uuid; 81 | } 82 | 83 | /** 84 | * Setter accessor for attribute 'uuid'. 85 | * @param uuid 86 | * new value for 'uuid ' 87 | */ 88 | public void setUuid(UUID uuid) { 89 | this.uuid = uuid; 90 | } 91 | 92 | /** 93 | * Getter accessor for attribute 'title'. 94 | * 95 | * @return 96 | * current value of 'title' 97 | */ 98 | public String getTitle() { 99 | return title; 100 | } 101 | 102 | /** 103 | * Setter accessor for attribute 'title'. 104 | * @param title 105 | * new value for 'title ' 106 | */ 107 | public void setTitle(String title) { 108 | this.title = title; 109 | } 110 | 111 | /** 112 | * Getter accessor for attribute 'order'. 113 | * 114 | * @return 115 | * current value of 'order' 116 | */ 117 | public int getOrder() { 118 | return order; 119 | } 120 | 121 | /** 122 | * Setter accessor for attribute 'order'. 123 | * @param order 124 | * new value for 'order ' 125 | */ 126 | public void setOrder(int order) { 127 | this.order = order; 128 | } 129 | 130 | /** 131 | * Getter accessor for attribute 'completed'. 132 | * 133 | * @return 134 | * current value of 'completed' 135 | */ 136 | public boolean isCompleted() { 137 | return completed; 138 | } 139 | 140 | /** 141 | * Setter accessor for attribute 'completed'. 142 | * @param completed 143 | * new value for 'completed ' 144 | */ 145 | public void setCompleted(boolean completed) { 146 | this.completed = completed; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/model/TodoAppSchema.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.model; 2 | 3 | /** 4 | * Having all schema info in a single place is a recommended 5 | * path when you need to update a column. 6 | * 7 | * Tips: Constants in interfaces can be inherited in multiple locations. 8 | * 9 | * @author Cedrick LUNVEN (@clunven) 10 | */ 11 | public interface TodoAppSchema { 12 | 13 | /** Constants for table todo_tasks */ 14 | String TABLE_TODO_TASKS = "todo_tasks"; 15 | String TASK_COL_UID = "uid"; 16 | String TASK_COL_TITLE = "title"; 17 | String TASK_COL_COMPLETED = "completed"; 18 | String TASK_COL_OFFSET = "offset"; 19 | 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/objectmapper/TaskDao.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.objectmapper; 2 | 3 | import java.util.Optional; 4 | import java.util.UUID; 5 | 6 | import com.datastax.oss.driver.api.core.PagingIterable; 7 | import com.datastax.oss.driver.api.mapper.annotations.Dao; 8 | import com.datastax.oss.driver.api.mapper.annotations.Delete; 9 | import com.datastax.oss.driver.api.mapper.annotations.Insert; 10 | import com.datastax.oss.driver.api.mapper.annotations.Query; 11 | import com.datastax.oss.driver.api.mapper.annotations.Select; 12 | import com.datastax.sample.model.TodoAppSchema; 13 | 14 | @Dao 15 | public interface TaskDao { 16 | 17 | @Select 18 | Optional findById(UUID taskId); 19 | 20 | @Insert 21 | void save(TaskEntity product); 22 | 23 | @Delete 24 | void delete(TaskEntity product); 25 | 26 | @Query("SELECT * FROM ${tableId}") 27 | PagingIterable findAll(); 28 | 29 | @Query("TRUNCATE TABLE " + TodoAppSchema.TABLE_TODO_TASKS) 30 | void deleteAll(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/objectmapper/TaskDaoMapper.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.objectmapper; 2 | 3 | import com.datastax.oss.driver.api.core.CqlIdentifier; 4 | import com.datastax.oss.driver.api.mapper.annotations.Dao; 5 | import com.datastax.oss.driver.api.mapper.annotations.DaoFactory; 6 | import com.datastax.oss.driver.api.mapper.annotations.DaoKeyspace; 7 | import com.datastax.oss.driver.api.mapper.annotations.Mapper; 8 | 9 | /** 10 | * Annotated as {@link Mapper} will generate working {@link Dao}. 11 | */ 12 | @Mapper 13 | public interface TaskDaoMapper { 14 | 15 | @DaoFactory 16 | TaskDao taskDao(@DaoKeyspace CqlIdentifier keyspace); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/objectmapper/TaskEntity.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.objectmapper; 2 | 3 | import java.io.Serializable; 4 | import java.util.UUID; 5 | 6 | import com.datastax.oss.driver.api.mapper.annotations.CqlName; 7 | import com.datastax.oss.driver.api.mapper.annotations.Entity; 8 | import com.datastax.oss.driver.api.mapper.annotations.PartitionKey; 9 | import com.datastax.sample.model.Task; 10 | import com.datastax.sample.model.TodoAppSchema; 11 | 12 | @Entity 13 | @CqlName(TodoAppSchema.TABLE_TODO_TASKS) 14 | public class TaskEntity implements Serializable, Comparable, TodoAppSchema { 15 | 16 | /** Serial. */ 17 | private static final long serialVersionUID = 6344665847226250633L; 18 | 19 | /** Unique id for the task. */ 20 | @CqlName(TASK_COL_UID) 21 | @PartitionKey 22 | private UUID uuid; 23 | 24 | /** Title. */ 25 | @CqlName(TASK_COL_TITLE) 26 | private String title; 27 | 28 | /** Status. */ 29 | @CqlName(TASK_COL_COMPLETED) 30 | private boolean completed = false; 31 | 32 | /** order field. */ 33 | @CqlName(TASK_COL_OFFSET) 34 | private int order = 0; 35 | 36 | /** 37 | * Constructors. 38 | */ 39 | public TaskEntity() {} 40 | 41 | public Task mapAsTask() { 42 | Task t = new Task(); 43 | t.setUuid(this.uuid); 44 | t.setCompleted(this.completed); 45 | t.setOrder(this.order); 46 | t.setTitle(this.title); 47 | return t; 48 | } 49 | 50 | public TaskEntity(Task t) { 51 | this.uuid = t.getUuid(); 52 | this.title = t.getTitle(); 53 | this.order = t.getOrder(); 54 | this.completed = t.isCompleted(); 55 | } 56 | 57 | /** {@inheritDoc} */ 58 | @Override 59 | public int compareTo(Task other) { 60 | if (other == null) 61 | return 1; 62 | return order - other.getOrder(); 63 | } 64 | 65 | /** 66 | * Getter accessor for attribute 'uuid'. 67 | * 68 | * @return current value of 'uuid' 69 | */ 70 | public UUID getUuid() { 71 | return uuid; 72 | } 73 | 74 | /** 75 | * Setter accessor for attribute 'uuid'. 76 | * 77 | * @param uuid 78 | * new value for 'uuid ' 79 | */ 80 | public void setUuid(UUID uuid) { 81 | this.uuid = uuid; 82 | } 83 | 84 | /** 85 | * Getter accessor for attribute 'title'. 86 | * 87 | * @return current value of 'title' 88 | */ 89 | public String getTitle() { 90 | return title; 91 | } 92 | 93 | /** 94 | * Setter accessor for attribute 'title'. 95 | * 96 | * @param title 97 | * new value for 'title ' 98 | */ 99 | public void setTitle(String title) { 100 | this.title = title; 101 | } 102 | 103 | /** 104 | * Getter accessor for attribute 'completed'. 105 | * 106 | * @return current value of 'completed' 107 | */ 108 | public boolean isCompleted() { 109 | return completed; 110 | } 111 | 112 | /** 113 | * Setter accessor for attribute 'completed'. 114 | * 115 | * @param completed 116 | * new value for 'completed ' 117 | */ 118 | public void setCompleted(boolean completed) { 119 | this.completed = completed; 120 | } 121 | 122 | /** 123 | * Getter accessor for attribute 'order'. 124 | * 125 | * @return current value of 'order' 126 | */ 127 | public int getOrder() { 128 | return order; 129 | } 130 | 131 | /** 132 | * Setter accessor for attribute 'order'. 133 | * 134 | * @param order 135 | * new value for 'order ' 136 | */ 137 | public void setOrder(int order) { 138 | this.order = order; 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepository.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.repository; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.UUID; 6 | 7 | import com.datastax.sample.model.Task; 8 | 9 | /** 10 | * Target of the workshop is to implement CRUD repository with multiple strategies 11 | * we defined this interface to have specifications. 12 | * 13 | * @author Cedrick LUNVEN (@clunven) 14 | */ 15 | public interface TodoListRepository { 16 | 17 | /** 18 | * Find a task from its unique identifier. 19 | */ 20 | Optional findById(UUID uid); 21 | 22 | /** 23 | * Create a new {@link Task} providing only a title. 24 | */ 25 | void upsert(Task title); 26 | 27 | /** 28 | * Delete a task identifier 29 | */ 30 | void delete(UUID uid); 31 | 32 | /** 33 | * List all available tasks. 34 | */ 35 | List < Task > findAll(); 36 | 37 | /** 38 | * Clean all records. 39 | */ 40 | void deleteAll(); 41 | 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepositoryCassandraDriverImpl.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.repository; 2 | 3 | import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.bindMarker; 4 | import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.deleteFrom; 5 | import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.selectFrom; 6 | import static com.datastax.oss.driver.api.querybuilder.QueryBuilder.truncate; 7 | import static com.datastax.oss.driver.api.querybuilder.relation.Relation.column; 8 | 9 | import java.util.Collections; 10 | import java.util.List; 11 | import java.util.Optional; 12 | import java.util.UUID; 13 | import java.util.stream.Collectors; 14 | 15 | import javax.annotation.PostConstruct; 16 | 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.stereotype.Repository; 19 | import org.springframework.util.Assert; 20 | 21 | import com.datastax.oss.driver.api.core.CqlSession; 22 | import com.datastax.oss.driver.api.core.cql.PreparedStatement; 23 | import com.datastax.oss.driver.api.core.cql.ResultSet; 24 | import com.datastax.oss.driver.api.core.cql.Row; 25 | import com.datastax.oss.driver.api.core.cql.SimpleStatement; 26 | import com.datastax.sample.model.Task; 27 | import com.datastax.sample.model.TodoAppSchema; 28 | 29 | /** 30 | * Default in-memory implementation of the repository. 31 | * 32 | * Help to have a working application even in the beginning. 33 | * 34 | * @author Cedrick LUNVEN (@clunven) 35 | */ 36 | //@Repository("todobackend.repo.cassandra-driver") 37 | public class TodoListRepositoryCassandraDriverImpl implements TodoListRepository, TodoAppSchema { 38 | 39 | @Autowired 40 | public CqlSession cqlSession; 41 | 42 | private PreparedStatement psFindTask; 43 | private PreparedStatement psFindAll; 44 | private PreparedStatement psDeleteTask; 45 | private PreparedStatement psDeleteAll; 46 | 47 | /** 48 | * Default constructor 49 | */ 50 | public TodoListRepositoryCassandraDriverImpl() {} 51 | 52 | /** 53 | * Constructoe with Sessions 54 | */ 55 | public TodoListRepositoryCassandraDriverImpl(CqlSession cqlSession) { 56 | this.cqlSession = cqlSession; 57 | initStatements(); 58 | } 59 | 60 | 61 | /** {@inheritDoc} */ 62 | @Override 63 | public void upsert(Task dto) { 64 | Assert.notNull(dto, "Task should not be null"); 65 | Assert.notNull(dto.getUuid(), "Task 'uid' shoudl not be null"); 66 | /* 67 | * No Prepared Statements Here simpy define the needed query. 68 | * 69 | * INSERT into todo_tasks(uid, title, offset, completed) 70 | * VALUES (uuid(), 'One', 1, true); 71 | */ 72 | SimpleStatement stmtInsertTask = SimpleStatement.builder("" 73 | + "INSERT INTO todo_tasks(uid, title, offset, completed)" 74 | + "VALUES (?, ?, ?, ?)") 75 | .addPositionalValue(dto.getUuid()) 76 | .addPositionalValue(dto.getTitle()) 77 | .addPositionalValue(dto.getOrder()) 78 | .addPositionalValue(dto.isCompleted()) 79 | .build(); 80 | cqlSession.execute(stmtInsertTask); 81 | } 82 | 83 | /** {@inheritDoc} */ 84 | @Override 85 | public List findAll() { 86 | List targetList = cqlSession.execute(psFindAll.bind()) 87 | .all().stream() 88 | .map(this::mapTaskRecord) 89 | .collect(Collectors.toList()); 90 | Collections.sort(targetList); // Sorting based on 'order' 91 | return targetList; 92 | } 93 | 94 | /** {@inheritDoc} */ 95 | @Override 96 | public void deleteAll() { 97 | cqlSession.execute(psDeleteAll.bind()); 98 | } 99 | 100 | /** {@inheritDoc} */ 101 | @Override 102 | public Optional findById(UUID uid) { 103 | Assert.notNull(uid, "Task uid should not be null nor empty"); 104 | ResultSet rs = cqlSession.execute(psFindTask.bind(uid)); 105 | Row taskrecord = rs.one(); // Request with primary key = unicity 106 | if (null == taskrecord) return Optional.empty(); 107 | return Optional.of(mapTaskRecord(taskrecord)); 108 | } 109 | 110 | /** {@inheritDoc} */ 111 | @Override 112 | public void delete(UUID uid) { 113 | Assert.notNull(uid, "Task uid should not be null nor empty"); 114 | cqlSession.execute(psDeleteTask.bind(uid)); 115 | } 116 | 117 | /** 118 | * You want to prepare you statements once to execute them faster later 119 | */ 120 | @PostConstruct 121 | public void initStatements() { 122 | if (psFindTask == null) { 123 | // SELECT * FROM todo_tasks where uid= d1d19715-a397-4975-bcb3-5107712db387; 124 | psFindTask = cqlSession.prepare( 125 | selectFrom(TABLE_TODO_TASKS).all() 126 | .where(column(TASK_COL_UID).isEqualTo(bindMarker(TASK_COL_UID))) 127 | .build()); 128 | } 129 | if (psFindAll == null) { 130 | // To empty a table, truncate is most performant 131 | psFindAll = cqlSession.prepare(selectFrom(TABLE_TODO_TASKS).all().build()); 132 | } 133 | if (psDeleteTask == null) { 134 | // DELETE FROM todo_tasks where uid= d1d19715-a397-4975-bcb3-5107712db387; 135 | psDeleteTask = cqlSession.prepare( 136 | deleteFrom(TABLE_TODO_TASKS) 137 | .where(column(TASK_COL_UID).isEqualTo(bindMarker(TASK_COL_UID))) 138 | .build()); 139 | } 140 | if (psDeleteAll == null) { 141 | // To empty a table, truncate is most performant 142 | psDeleteAll = cqlSession.prepare(truncate(TABLE_TODO_TASKS).build()); 143 | } 144 | } 145 | 146 | /** 147 | * Mapping from Cassandra Record to Object 148 | */ 149 | private Task mapTaskRecord(Row taskRecord) { 150 | Task task = new Task(); 151 | task.setUuid(taskRecord.getUuid(TASK_COL_UID)); 152 | task.setTitle(taskRecord.getString(TASK_COL_TITLE)); 153 | task.setCompleted(taskRecord.getBoolean(TASK_COL_COMPLETED)); 154 | task.setOrder(taskRecord.getInt(TASK_COL_OFFSET)); 155 | return task; 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepositoryInMemoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.repository; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | 10 | import javax.annotation.PostConstruct; 11 | 12 | import org.springframework.stereotype.Repository; 13 | 14 | import com.datastax.sample.model.Task; 15 | 16 | /** 17 | * Default in-memory implementation of the repository. 18 | * 19 | * Help to have a working application even in the beginning. 20 | * 21 | * @author Cedrick LUNVEN (@clunven) 22 | */ 23 | @Repository("todobackend.repo.inmemory") 24 | public class TodoListRepositoryInMemoryImpl implements TodoListRepository { 25 | 26 | /** This will be our storage in memory. */ 27 | private Map mapOfTasks = new ConcurrentHashMap<>(); 28 | 29 | /** {@inheritDoc} */ 30 | @Override 31 | public List findAll() { 32 | return new ArrayList<>(mapOfTasks.values()); 33 | } 34 | 35 | /** {@inheritDoc} */ 36 | @Override 37 | public void deleteAll() { 38 | mapOfTasks.clear(); 39 | } 40 | 41 | /** {@inheritDoc} */ 42 | @Override 43 | public Optional findById(UUID uid) { 44 | if (null == uid) return Optional.empty(); 45 | return Optional.ofNullable(mapOfTasks.get(uid)); 46 | } 47 | 48 | /** {@inheritDoc} */ 49 | @Override 50 | public void upsert(Task dto) { 51 | if (null != dto) { 52 | mapOfTasks.put(dto.getUuid(), dto); 53 | } 54 | } 55 | 56 | /** {@inheritDoc} */ 57 | @Override 58 | public void delete(UUID uid) { 59 | mapOfTasks.remove(uid); 60 | } 61 | 62 | @PostConstruct 63 | public void populate() { 64 | Task one = new Task("Local backend API task1"); 65 | one.setUuid(UUID.fromString("6f6c5b47-4e23-4437-ada8-d0a6f79330a2")); 66 | Task two = new Task("Local backend API task2"); 67 | Task three = new Task("Local backend API task3"); 68 | mapOfTasks.put(one.getUuid(), one); 69 | mapOfTasks.put(two.getUuid(), two); 70 | mapOfTasks.put(three.getUuid(), three); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepositoryObjectMapperImpl.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.repository; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.UUID; 6 | import java.util.stream.Collectors; 7 | 8 | import org.springframework.stereotype.Repository; 9 | 10 | import com.datastax.oss.driver.api.core.CqlSession; 11 | import com.datastax.sample.model.Task; 12 | import com.datastax.sample.objectmapper.TaskDao; 13 | import com.datastax.sample.objectmapper.TaskDaoMapperBuilder; 14 | import com.datastax.sample.objectmapper.TaskEntity; 15 | 16 | /** 17 | * Default in-memory implementation of the repository. 18 | * 19 | * Help to have a working application even in the beginning. 20 | * 21 | * @author Cedrick LUNVEN (@clunven) 22 | */ 23 | //@Repository("todobackend.repo.cassandra-object-mapper") 24 | public class TodoListRepositoryObjectMapperImpl implements TodoListRepository { 25 | 26 | /** CqlSession holding metadata to interact with Cassandra. */ 27 | private TaskDao taskDao; 28 | 29 | /** External Initialization. */ 30 | public TodoListRepositoryObjectMapperImpl(CqlSession cqlSession) { 31 | taskDao = new TaskDaoMapperBuilder(cqlSession) 32 | .build().taskDao(cqlSession.getKeyspace().get()); 33 | } 34 | 35 | /** {@inheritDoc} */ 36 | @Override 37 | public List findAll() { 38 | return taskDao.findAll().all().stream() 39 | .map(TaskEntity::mapAsTask) 40 | .collect(Collectors.toList()); 41 | } 42 | 43 | /** {@inheritDoc} */ 44 | @Override 45 | public void deleteAll() { 46 | taskDao.deleteAll(); 47 | } 48 | 49 | /** {@inheritDoc} */ 50 | @Override 51 | public Optional findById(UUID uid) { 52 | if (null == uid) return Optional.empty(); 53 | Optional entity = taskDao.findById(uid); 54 | if (entity.isEmpty()) return Optional.empty(); 55 | return Optional.ofNullable(entity.get().mapAsTask()); 56 | } 57 | 58 | /** {@inheritDoc} */ 59 | @Override 60 | public void upsert(Task dto) { 61 | if (null != dto) { 62 | taskDao.save(new TaskEntity(dto)); 63 | } 64 | } 65 | 66 | /** {@inheritDoc} */ 67 | @Override 68 | public void delete(UUID uid) { 69 | TaskEntity te = new TaskEntity(); 70 | te.setUuid(uid); 71 | taskDao.delete(te); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/repository/TodoListRepositorySpringDataImpl.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.repository; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.UUID; 6 | import java.util.stream.Collectors; 7 | 8 | import org.springframework.stereotype.Repository; 9 | 10 | import com.datastax.sample.model.Task; 11 | import com.datastax.sample.springdata.TaskSpringData; 12 | //import com.datastax.sample.springdata.TaskSpringDataRepository; 13 | 14 | /** 15 | * Default in-memory implementation of the repository. 16 | * 17 | * Help to have a working application even in the beginning. 18 | * 19 | * @author Cedrick LUNVEN (@clunven) 20 | */ 21 | /* 22 | @Repository("todobackend.repo.spring-data-cassandra") 23 | public class TodoListRepositorySpringDataImpl implements TodoListRepository { 24 | 25 | private TaskSpringDataRepository taskDao; 26 | 27 | public TodoListRepositorySpringDataImpl(TaskSpringDataRepository taskDao) { 28 | this.taskDao = taskDao; 29 | } 30 | 31 | @Override 32 | public List findAll() { 33 | return taskDao.findAll().stream() 34 | .map(TaskSpringData::mapAsTask) 35 | .collect(Collectors.toList()); 36 | } 37 | 38 | @Override 39 | public void deleteAll() { 40 | taskDao.deleteAll(); 41 | } 42 | 43 | @Override 44 | public Optional findById(UUID uid) { 45 | if (null == uid) return Optional.empty(); 46 | Optional entity = taskDao.findById(uid); 47 | if (entity.isEmpty()) return Optional.empty(); 48 | return Optional.ofNullable(entity.get().mapAsTask()); 49 | } 50 | 51 | @Override 52 | public void upsert(Task dto) { 53 | if (null != dto) { 54 | taskDao.save(new TaskSpringData(dto)); 55 | } 56 | } 57 | 58 | @Override 59 | public void delete(UUID uid) { 60 | TaskSpringData tsd = new TaskSpringData(); 61 | tsd.setUuid(uid); 62 | taskDao.delete(tsd); 63 | } 64 | }*/ 65 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/resources/HomeController.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.resources; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | import static org.springdoc.core.Constants.SWAGGER_UI_PATH; 8 | import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR; 9 | import static org.springframework.web.servlet.view.UrlBasedViewResolver.REDIRECT_URL_PREFIX; 10 | 11 | /** 12 | * Home = API documentation page 13 | */ 14 | @Controller 15 | public class HomeController { 16 | 17 | @Value(SWAGGER_UI_PATH) 18 | private String swaggerUiPath; 19 | 20 | @GetMapping(DEFAULT_PATH_SEPARATOR) 21 | public String index() { 22 | return REDIRECT_URL_PREFIX + swaggerUiPath; 23 | } 24 | } -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/resources/TodoListRestController.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.resources; 2 | 3 | import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; 4 | import static org.springframework.web.bind.annotation.RequestMethod.DELETE; 5 | import static org.springframework.web.bind.annotation.RequestMethod.GET; 6 | import static org.springframework.web.bind.annotation.RequestMethod.OPTIONS; 7 | import static org.springframework.web.bind.annotation.RequestMethod.PATCH; 8 | import static org.springframework.web.bind.annotation.RequestMethod.POST; 9 | import static org.springframework.web.bind.annotation.RequestMethod.PUT; 10 | 11 | import java.net.URI; 12 | import java.net.URISyntaxException; 13 | import java.util.List; 14 | import java.util.Optional; 15 | import java.util.UUID; 16 | import java.util.stream.Collectors; 17 | 18 | import javax.servlet.http.HttpServletRequest; 19 | 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.beans.factory.annotation.Qualifier; 24 | import org.springframework.http.HttpStatus; 25 | import org.springframework.http.ResponseEntity; 26 | import org.springframework.util.Assert; 27 | import org.springframework.web.bind.annotation.CrossOrigin; 28 | import org.springframework.web.bind.annotation.ExceptionHandler; 29 | import org.springframework.web.bind.annotation.PathVariable; 30 | import org.springframework.web.bind.annotation.RequestBody; 31 | import org.springframework.web.bind.annotation.RequestMapping; 32 | import org.springframework.web.bind.annotation.ResponseStatus; 33 | import org.springframework.web.bind.annotation.RestController; 34 | 35 | import com.datastax.oss.driver.api.core.DriverException; 36 | import com.datastax.sample.model.Task; 37 | import com.datastax.sample.model.TaskBody; 38 | import com.datastax.sample.model.TaskResource; 39 | import com.datastax.sample.repository.TodoListRepository; 40 | 41 | import io.swagger.v3.oas.annotations.Operation; 42 | import io.swagger.v3.oas.annotations.Parameter; 43 | import io.swagger.v3.oas.annotations.media.ArraySchema; 44 | import io.swagger.v3.oas.annotations.media.Content; 45 | import io.swagger.v3.oas.annotations.media.Schema; 46 | import io.swagger.v3.oas.annotations.responses.ApiResponse; 47 | import io.swagger.v3.oas.annotations.responses.ApiResponses; 48 | import io.swagger.v3.oas.annotations.tags.Tag; 49 | 50 | @CrossOrigin( 51 | methods = {PUT, POST, GET, OPTIONS, DELETE, PATCH}, 52 | maxAge = 3600, 53 | allowedHeaders = {"x-requested-with", "origin", "content-type", "accept"}, 54 | origins = "*" 55 | ) 56 | @RestController 57 | @RequestMapping("/api/v1/todos") 58 | @Tag(name = "Todos", description = "Implement CRUD operations for Todo Tasks") 59 | public class TodoListRestController { 60 | 61 | /** Logger for the class. */ 62 | private static final Logger logger = LoggerFactory.getLogger(TodoListRestController.class); 63 | 64 | @Autowired 65 | @Qualifier("todobackend.repo.inmemory") 66 | //@Qualifier("todobackend.repo.cassandra-driver") 67 | //@Qualifier("todobackend.repo.cassandra-object-mapper") 68 | //@Qualifier("todobackend.repo.spring-data-cassandra") 69 | private TodoListRepository todoRepository; 70 | 71 | /** 72 | * Default constructor. 73 | */ 74 | public TodoListRestController() {} 75 | 76 | /** 77 | * Constructor. 78 | */ 79 | public TodoListRestController(TodoListRepository todoRepository) { 80 | this.todoRepository = todoRepository; 81 | } 82 | 83 | // --- Operation on the list -- 84 | 85 | /** 86 | * Retrieve all tasks (GET) 87 | */ 88 | @Operation( 89 | summary = "Retrieve the complete list of Taskss", 90 | description = "List all records in the tables", 91 | tags = { "todos" }) 92 | @ApiResponses(value = { 93 | @ApiResponse(responseCode = "200", 94 | description = "The list has been retrieved even if empty no error", 95 | content = @Content(array = @ArraySchema(schema = @Schema(implementation = TaskResource.class)))) }) 96 | @RequestMapping( 97 | value = "/", 98 | method = GET, 99 | produces = APPLICATION_JSON_VALUE) 100 | public ResponseEntity> findAll(HttpServletRequest request) { 101 | logger.info("List all task in the db: {}", rewriteUrl(request) + "?" + request.getQueryString()); 102 | return ResponseEntity.ok(todoRepository.findAll() 103 | .stream().map(dto -> new TaskResource(rewriteUrl(request) + dto.getUuid(), dto)) 104 | .collect(Collectors.toList())); 105 | } 106 | 107 | /** 108 | * Delete all tasks (DELETE) 109 | */ 110 | @Operation( 111 | summary = "Delete all tasks in one go", 112 | description = "Clear the storage", 113 | tags = { "todos", "delete" }) 114 | @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "No results") } ) 115 | @RequestMapping(value = "/", method = DELETE) 116 | public ResponseEntity deleteAll(HttpServletRequest request) { 117 | logger.info("Delete all task in the db: {}", rewriteUrl(request) + "?" + request.getQueryString()); 118 | todoRepository.deleteAll(); 119 | return new ResponseEntity<>(HttpStatus.NO_CONTENT); 120 | } 121 | 122 | // --- Unitary operation -- 123 | 124 | /** 125 | * CREATE = Create a new Task (POST) 126 | */ 127 | @Operation( 128 | summary = "Create a new task", 129 | description = "POST is the proper http verb when you cannot provide the full URL (including id)", 130 | tags = { "create" }) 131 | @ApiResponses(value = { 132 | @ApiResponse(responseCode = "201", 133 | description = "The task has been successfully created", 134 | content = @Content(schema = @Schema(implementation = TaskResource.class))), 135 | @ApiResponse(responseCode = "400", description = "Title is blank but is mandatory"), 136 | @ApiResponse(responseCode = "500", description = "An error occur in storage") }) 137 | @RequestMapping( 138 | value = "/", 139 | method = POST, 140 | produces = APPLICATION_JSON_VALUE, 141 | consumes = APPLICATION_JSON_VALUE) 142 | public ResponseEntity create(HttpServletRequest request, 143 | @RequestBody 144 | @io.swagger.v3.oas.annotations.parameters.RequestBody( 145 | description = "Only field title is required in the following JSON object", 146 | required = true, 147 | content = @Content(schema = @Schema(implementation = TaskBody.class))) 148 | TaskBody taskCreationRequest) 149 | throws URISyntaxException { 150 | Assert.notNull(taskCreationRequest, "You must provide a Task in BODY"); 151 | Assert.hasLength(taskCreationRequest.getTitle(), "Title is a required field to create a task"); 152 | logger.info("Create new Task at {} with title {}", 153 | request.getRequestURL().toString(), taskCreationRequest.getTitle()); 154 | Task dto = new Task(UUID.randomUUID(), 155 | taskCreationRequest.getTitle(), 156 | taskCreationRequest.isCompleted(), 157 | taskCreationRequest.getOrder()); 158 | todoRepository.upsert(dto); 159 | // Created 160 | TaskResource bean = new TaskResource(rewriteUrl(request) + dto.getUuid(), dto); 161 | return ResponseEntity.created(new URI(bean.getUrl())).body(bean); 162 | } 163 | 164 | /** 165 | * READ = Find a Task by its id (GET) 166 | */ 167 | @RequestMapping( 168 | value = "/{taskId}", 169 | method = GET, 170 | produces = APPLICATION_JSON_VALUE) 171 | @Operation( 172 | summary = "Get details of a task if exists", 173 | description = "Retrieve a tasks based on its identifier", 174 | tags = { "Task" }) 175 | @ApiResponses(value = { 176 | @ApiResponse(responseCode = "200", description = "Successful operation", 177 | content = @Content(schema = @Schema(implementation = TaskResource.class))), 178 | @ApiResponse(responseCode = "400", description = "UUID is blank or contains invalid characters (expecting valid UUID)"), 179 | @ApiResponse(responseCode = "404", description = "Task not found") }) 180 | public ResponseEntity read(HttpServletRequest request, 181 | @Parameter(name="taskId", 182 | description="Unique identifier for the task", 183 | example = "6f6c5b47-4e23-4437-ada8-d0a6f79330a2", 184 | required=true ) 185 | @PathVariable(value = "taskId") String taskId) { 186 | logger.info("Find a task with its id {}", rewriteUrl(request) + "?" + request.getQueryString()); 187 | Assert.hasLength(taskId, "TaskId id is required and should not be null"); 188 | Optional myTask = todoRepository.findById(UUID.fromString(taskId)); 189 | // Routing Result 190 | if (!myTask.isPresent()) { 191 | logger.warn("Task with uid {} has not been found", taskId); 192 | return ResponseEntity.notFound().build(); 193 | } 194 | return ResponseEntity.ok(new TaskResource(rewriteUrl(request), myTask.get())); 195 | } 196 | 197 | /** 198 | * Update an existing Task (PATCH) 199 | */ 200 | @Operation( 201 | summary = "Update an existing task", 202 | description = "PATCH when you have id and providing body", 203 | tags = { "update" }) 204 | @ApiResponses(value = { 205 | @ApiResponse(responseCode = "200", description = "Successful operation", 206 | content = @Content(schema = @Schema(implementation = TaskResource.class))), 207 | @ApiResponse(responseCode = "400", description = "Json body not valid"), 208 | @ApiResponse(responseCode = "404", description = "Task UUID not found") }) 209 | @RequestMapping( 210 | value = "/{taskId}", 211 | method = PATCH, 212 | produces = APPLICATION_JSON_VALUE, 213 | consumes = APPLICATION_JSON_VALUE) 214 | public ResponseEntity update(HttpServletRequest request, 215 | @Parameter(name="taskId", required=true, 216 | description="Unique identifier for the task", 217 | example = "6f6c5b47-4e23-4437-ada8-d0a6f79330a2") 218 | @PathVariable(value = "taskId") String taskId, 219 | @RequestBody 220 | @io.swagger.v3.oas.annotations.parameters.RequestBody( 221 | description = "Update all fields if needed", 222 | required = true, 223 | content = @Content(schema = @Schema(implementation = TaskBody.class))) 224 | TaskBody taskBody) 225 | throws URISyntaxException { 226 | Assert.notNull(taskBody, "You must provide a Task in BODY"); 227 | logger.info("Updating task {}", taskId); 228 | Optional myTask = todoRepository.findById(UUID.fromString(taskId)); 229 | // Routing Result 230 | if (!myTask.isPresent()) { 231 | logger.warn("Task with uid {} has not been found", taskId); 232 | return ResponseEntity.notFound().build(); 233 | } 234 | Task existing = myTask.get(); 235 | String newTitle = taskBody.getTitle(); 236 | if (null != newTitle && !"".equals(newTitle)) { 237 | existing.setTitle(newTitle); 238 | } 239 | existing.setCompleted(taskBody.isCompleted()); 240 | existing.setOrder(taskBody.getOrder()); 241 | todoRepository.upsert(existing); 242 | return ResponseEntity.ok(new TaskResource(rewriteUrl(request), existing)); 243 | } 244 | 245 | /** 246 | * Delete a Task by its id 247 | */ 248 | @RequestMapping(value = "/{taskId}", method = DELETE) 249 | @Operation(summary = "Delete a task from its id of exists", description = "Delete a task from its id of exists") 250 | @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "No results") } ) 251 | public ResponseEntity delete(HttpServletRequest request, 252 | @Parameter(name="taskId", required=true, 253 | description="Unique identifier for the task", 254 | example = "6f6c5b47-4e23-4437-ada8-d0a6f79330a2") 255 | @PathVariable(value = "taskId") String taskId) { 256 | logger.info("Delete a task with its id {}", request.getRequestURL().toString()); 257 | Assert.hasLength(taskId, "TaskId id is required and should not be null"); 258 | Optional myTask = todoRepository.findById(UUID.fromString(taskId)); 259 | // Routing Result 260 | if (!myTask.isPresent()) { 261 | logger.warn("Task with uid {} has not been found", taskId); 262 | return ResponseEntity.notFound().build(); 263 | } 264 | todoRepository.delete(UUID.fromString(taskId)); 265 | return new ResponseEntity<>(HttpStatus.NO_CONTENT); 266 | } 267 | 268 | /** 269 | * Converts {@link IllegalArgumentException} into HTTP 400 bad parameter 270 | * the response body. 271 | * 272 | * @param e The {@link DriverException}. 273 | * @return The error message to be used as response body. 274 | */ 275 | @ExceptionHandler(value = IllegalArgumentException.class) 276 | @ResponseStatus(value = HttpStatus.BAD_REQUEST) 277 | public String _errorBadRequestHandler(IllegalArgumentException ex) { 278 | return "Invalid Parameter: " + ex.getMessage(); 279 | } 280 | 281 | /** 282 | * Converts {@link DriverException} into HTTP 500 error codes and outputs the error message as 283 | * the response body. 284 | * 285 | * @param e The {@link DriverException}. 286 | * @return The error message to be used as response body. 287 | */ 288 | @ExceptionHandler(DriverException.class) 289 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) 290 | public String _errorDriverHandler(DriverException e) { 291 | return e.getMessage(); 292 | } 293 | 294 | /** 295 | * As isSecure is still false and https is enforce by gitpod let's 296 | * change it. 297 | */ 298 | private String rewriteUrl(HttpServletRequest request) { 299 | String myUrl = request.getRequestURL().toString(); 300 | if (myUrl.contains("gitpod")) { 301 | myUrl = myUrl.replaceAll("http", "https"); 302 | } 303 | return myUrl; 304 | } 305 | 306 | } 307 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/springdata/TaskSpringData.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.springdata; 2 | 3 | import java.io.Serializable; 4 | import java.util.UUID; 5 | 6 | //import org.springframework.data.cassandra.core.cql.PrimaryKeyType; 7 | //import org.springframework.data.cassandra.core.mapping.CassandraType; 8 | //import org.springframework.data.cassandra.core.mapping.CassandraType.Name; 9 | //import org.springframework.data.cassandra.core.mapping.Column; 10 | //import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; 11 | //import org.springframework.data.cassandra.core.mapping.Table; 12 | 13 | import com.datastax.sample.model.Task; 14 | import com.datastax.sample.model.TodoAppSchema; 15 | 16 | /** 17 | * Entity for table and Spring Data. 18 | * 19 | * @author Cedrick LUNVEN (@clunven) 20 | */ 21 | //@Table(value = TodoAppSchema.TABLE_TODO_TASKS) 22 | public class TaskSpringData implements Serializable, Comparable, TodoAppSchema { 23 | 24 | private static final long serialVersionUID = -5844442448334944278L; 25 | 26 | //@PrimaryKeyColumn( 27 | // name = TodoAppSchema.TASK_COL_UID, ordinal = 0, 28 | // type = PrimaryKeyType.PARTITIONED) 29 | //@CassandraType(type = Name.UUID) 30 | private UUID uuid; 31 | 32 | //@Column(TASK_COL_TITLE) 33 | //@CassandraType(type = Name.TEXT) 34 | private String title; 35 | 36 | //@Column(TASK_COL_COMPLETED) 37 | //@CassandraType(type = Name.BOOLEAN) 38 | private boolean completed = false; 39 | 40 | //@Column(TASK_COL_OFFSET) 41 | //@CassandraType(type = Name.INT) 42 | private int order = 0; 43 | 44 | public TaskSpringData() {} 45 | 46 | public Task mapAsTask() { 47 | Task t = new Task(); 48 | t.setUuid(this.uuid); 49 | t.setCompleted(this.completed); 50 | t.setOrder(this.order); 51 | t.setTitle(this.title); 52 | return t; 53 | } 54 | 55 | public TaskSpringData(Task t) { 56 | this.uuid = t.getUuid(); 57 | this.title = t.getTitle(); 58 | this.order = t.getOrder(); 59 | this.completed = t.isCompleted(); 60 | } 61 | 62 | /** {@inheritDoc} */ 63 | @Override 64 | public int compareTo(Task other) { 65 | if (other == null) 66 | return 1; 67 | return order - other.getOrder(); 68 | } 69 | 70 | /** 71 | * Getter accessor for attribute 'uuid'. 72 | * 73 | * @return current value of 'uuid' 74 | */ 75 | public UUID getUuid() { 76 | return uuid; 77 | } 78 | 79 | /** 80 | * Setter accessor for attribute 'uuid'. 81 | * 82 | * @param uuid 83 | * new value for 'uuid ' 84 | */ 85 | public void setUuid(UUID uuid) { 86 | this.uuid = uuid; 87 | } 88 | 89 | /** 90 | * Getter accessor for attribute 'title'. 91 | * 92 | * @return current value of 'title' 93 | */ 94 | public String getTitle() { 95 | return title; 96 | } 97 | 98 | /** 99 | * Setter accessor for attribute 'title'. 100 | * 101 | * @param title 102 | * new value for 'title ' 103 | */ 104 | public void setTitle(String title) { 105 | this.title = title; 106 | } 107 | 108 | /** 109 | * Getter accessor for attribute 'completed'. 110 | * 111 | * @return current value of 'completed' 112 | */ 113 | public boolean isCompleted() { 114 | return completed; 115 | } 116 | 117 | /** 118 | * Setter accessor for attribute 'completed'. 119 | * 120 | * @param completed 121 | * new value for 'completed ' 122 | */ 123 | public void setCompleted(boolean completed) { 124 | this.completed = completed; 125 | } 126 | 127 | /** 128 | * Getter accessor for attribute 'order'. 129 | * 130 | * @return current value of 'order' 131 | */ 132 | public int getOrder() { 133 | return order; 134 | } 135 | 136 | /** 137 | * Setter accessor for attribute 'order'. 138 | * 139 | * @param order 140 | * new value for 'order ' 141 | */ 142 | public void setOrder(int order) { 143 | this.order = order; 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/java/com/datastax/sample/springdata/TaskSpringDataRepository.java: -------------------------------------------------------------------------------- 1 | package com.datastax.sample.springdata; 2 | 3 | import java.util.Optional; 4 | import java.util.UUID; 5 | 6 | //import org.springframework.data.cassandra.repository.CassandraRepository; 7 | //import org.springframework.data.cassandra.repository.Query; 8 | //import org.springframework.stereotype.Repository; 9 | 10 | import com.datastax.sample.model.TodoAppSchema; 11 | 12 | /* 13 | @Repository("todobackend.repo.spring") 14 | public interface TaskSpringDataRepository 15 | extends TodoAppSchema, CassandraRepository { 16 | 17 | @Query("SELECT * FROM " + TodoAppSchema.TABLE_TODO_TASKS + 18 | " WHERE " + TodoAppSchema.TASK_COL_UID + " = ?0") 19 | Optional findByTaskByIdO(UUID taskid); 20 | 21 | } 22 | */ 23 | 24 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/resources/application.conf: -------------------------------------------------------------------------------- 1 | datastax-java-driver { 2 | 3 | basic { 4 | request { 5 | timeout = 8 seconds 6 | consistency = LOCAL_QUORUM 7 | page-size = 5000 8 | } 9 | session-keyspace = todoapp 10 | cloud { 11 | secure-connect-bundle = /Users/cedricklunven/Downloads/secure-connect-dev-workshop-db.zip 12 | } 13 | } 14 | 15 | advanced { 16 | auth-provider { 17 | class = PlainTextAuthProvider 18 | username = todouser 19 | password = todopassword 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: ${PORT:8080} 3 | 4 | # Documentation 5 | springdoc: 6 | api-docs: 7 | enabled: true 8 | groups: 9 | enabled: true 10 | swagger-ui: 11 | path: /swagger-ui.html 12 | display-request-duration: true 13 | groups-order: DESC 14 | version: 1.0-SNAPSHOT 15 | show-actuator: true 16 | group-configs: 17 | - group: Rest Controllers (Spring MVC) 18 | packages-to-scan: com.datastax.sample.resources 19 | 20 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | 2 | ${AnsiColor.BLUE} ________ __ __ __ .__ 3 | ${AnsiColor.BLUE} \______ \ _______ __/ \ / \ | __ _____| |__ ____ ______ 4 | ${AnsiColor.BLUE} | | \_/ __ \ \/ /\ \/\/ / |/ / / ___/ | \ / _ \\____ \ 5 | ${AnsiColor.BLUE} | ` \ ___/\ / \ /| < \___ \| Y ( <_> ) |_> > 6 | ${AnsiColor.BLUE} /_______ /\___ >\_/ \__/\ / |__|_ \/____ >___| /\____/| __/ 7 | ${AnsiColor.BLUE} \/ \/ \/ \/ \/ \/ |__| 8 | 9 | ${AnsiColor.CYAN} Backend API implementation of todobackend.com 10 | ${AnsiColor.CYAN} We are using SpringBoot and Apache Cassandra 11 | 12 | ${AnsiColor.GREEN} The application is started at ${AnsiColor.RED}http://localhost:8080 13 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} %magenta(%-5level) %cyan(%-50logger) : %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/main/resources/sample-data.cql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS products (id UUID PRIMARY KEY,name text,description text, price decimal, created timestamp); 2 | CREATE TABLE IF NOT EXISTS timeseries_daily (source text,yyyymmdd text, tick timestamp, value double, PRIMARY KEY ((source,yyyymmdd), tick)) WITH CLUSTERING ORDER BY (tick DESC); 3 | 4 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb0,'Heavy Lift Arms', 'Heavy lift arms capable of lifting 1,250 lbs of weight per arm. Sold as a set.',4199.99,'2019-01-10 09:48:31.020+0040'); 5 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb1,'Precision Action Arms','Arms for precision activities in manufacturing or repair. Sold as a set.',12199.99,'2019-01-10 09:28:31.020+0040'); 6 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb2,'Medium Lift Arms','Medium lift arms capable of lifting 850 lbs of weight per arm. Sold as a set.',3199.99,'2019-01-10 09:23:31.020+0040'); 7 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb3,'Drill Arms','Arms for drilling into surface material. Sold as a set. Does not include drill bits.',2199.99,'2019-01-10 09:12:31.020+0040'); 8 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb4,'High Process AI CPU','Head processor unit for robot with heavy AI job process capabilities.',2199.99,'2019-01-10 18:48:31.020+0040'); 9 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb5,'Basic Task CPU','Head processor unit for robot with basic process tasks.',899.99,'2019-01-10 18:48:31.020+0040'); 10 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb6,'High Strength Torso','Robot body with reinforced plate to handle heavy workload and weight during jobs.',2199.99,'2019-01-10 18:48:31.020+0040'); 11 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb7,'Medium Strength Torso','Robot body to handle general jobs.',1999.99,'2019-01-10 18:48:31.020+0040'); 12 | INSERT INTO betterbotz.products ( id , name , description, price, created ) VALUES (31047029-2175-43ce-9fdd-b3d568b19bb8,'Precision Torso','Robot torso built to handle precision jobs with extra stability and accuracy reinforcement.',8199.99,'2019-01-10 18:48:31.020+0040'); 13 | 14 | INSERT INTO betterbotz.timeseries_daily (source , yyyymmdd , tick, value) VALUES ('sensor_X','20200501',1590084479687,0.1); 15 | INSERT INTO betterbotz.timeseries_daily (source , yyyymmdd , tick, value) VALUES ('sensor_X','20200501',1590084479688,0.2); 16 | INSERT INTO betterbotz.timeseries_daily (source , yyyymmdd , tick, value) VALUES ('sensor_X','20200501',1590084479689,0.5); 17 | INSERT INTO betterbotz.timeseries_daily (source , yyyymmdd , tick, value) VALUES ('sensor_X','20200501',1590084479690,0.5); 18 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/test/java/com/datastax/samples/astra/ConnectivityToAstraExplicitTest.java: -------------------------------------------------------------------------------- 1 | package com.datastax.samples.astra; 2 | 3 | import java.io.File; 4 | import java.nio.file.Paths; 5 | 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.DisplayName; 8 | import org.junit.jupiter.api.Test; 9 | import org.junit.platform.runner.JUnitPlatform; 10 | import org.junit.runner.RunWith; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import com.datastax.oss.driver.api.core.CqlSession; 15 | 16 | /** 17 | * First Connectivity test with Astra. 18 | * 19 | * @author Cedrick LUNVEN (@clunven) 20 | */ 21 | @RunWith(JUnitPlatform.class) 22 | public class ConnectivityToAstraExplicitTest { 23 | 24 | /** Logger for the class. */ 25 | private static Logger LOGGER = LoggerFactory.getLogger(ConnectivityToAstraExplicitTest.class); 26 | 27 | /** Settings. */ 28 | public static String ASTRA_ZIP_FILE = "/Users/cedricklunven/Downloads/secure-connect-dev-workshop-db.zip"; 29 | public static String ASTRA_USERNAME = "todouser"; 30 | public static String ASTRA_PASSWORD = "todopassword"; 31 | public static String ASTRA_KEYSPACE = "todoapp"; 32 | 33 | @Test 34 | @DisplayName("Test connectivity to Astra explicit values") 35 | public void should_connect_to_Astra_static() { 36 | 37 | // Given interface is properly populated 38 | Assertions.assertTrue(new File(ASTRA_ZIP_FILE).exists(), 39 | "File '" + ASTRA_ZIP_FILE + "' has not been found\n" 40 | + "To run this sample you need to download the secure bundle file from ASTRA WebPage\n" 41 | + "More info here:"); 42 | 43 | // When connecting to ASTRA 44 | try (CqlSession cqlSession = CqlSession.builder() 45 | //.addContactPoint(new InetSocketAddress("127.0.0.1", 9042)) 46 | .withCloudSecureConnectBundle(Paths.get(ASTRA_ZIP_FILE)) 47 | .withAuthCredentials(ASTRA_USERNAME, ASTRA_PASSWORD) 48 | .withKeyspace(ASTRA_KEYSPACE) 49 | .build()) { 50 | 51 | // Then connection is successfull 52 | LOGGER.info(" + [OK] - Connection Established to Astra with Keyspace {}", 53 | cqlSession.getKeyspace().get()); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/test/java/com/datastax/samples/astra/ConnectivityToAstraWithConfTest.java: -------------------------------------------------------------------------------- 1 | package com.datastax.samples.astra; 2 | 3 | import java.io.File; 4 | 5 | import org.junit.jupiter.api.DisplayName; 6 | import org.junit.jupiter.api.Test; 7 | import org.junit.platform.runner.JUnitPlatform; 8 | import org.junit.runner.RunWith; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import com.datastax.oss.driver.api.core.CqlSession; 13 | import com.datastax.oss.driver.api.core.config.DriverConfigLoader; 14 | 15 | /** 16 | * First Connectivity test with Astra. 17 | * 18 | * @author Cedrick LUNVEN (@clunven) 19 | */ 20 | @RunWith(JUnitPlatform.class) 21 | public class ConnectivityToAstraWithConfTest { 22 | 23 | /** Logger for the class. */ 24 | private static Logger LOGGER = LoggerFactory.getLogger(ConnectivityToAstraWithConfTest.class); 25 | 26 | @Test 27 | @DisplayName("Test connectivity to Astra delegate file") 28 | public void should_connect_to_Astra_withConfig() { 29 | 30 | // Config loader from file 31 | DriverConfigLoader loader = DriverConfigLoader.fromFile( 32 | new File(ConnectivityToAstraWithConfTest.class.getResource("/application_test.conf").getFile())); 33 | 34 | // Use it to create the session 35 | try (CqlSession cqlSession = CqlSession.builder().withConfigLoader(loader).build()) { 36 | LOGGER.info(" + [OK] - Connection Established to Astra with Keyspace {}", 37 | cqlSession.getKeyspace().get()); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/test/java/com/datastax/samples/astra/CreateSchemaInAstraTest.java: -------------------------------------------------------------------------------- 1 | package com.datastax.samples.astra; 2 | 3 | import java.io.File; 4 | 5 | import org.junit.jupiter.api.Test; 6 | import org.junit.platform.runner.JUnitPlatform; 7 | import org.junit.runner.RunWith; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import com.datastax.oss.driver.api.core.CqlSession; 12 | import com.datastax.oss.driver.api.core.config.DriverConfigLoader; 13 | import com.datastax.oss.driver.api.core.cql.SimpleStatement; 14 | import com.datastax.oss.driver.api.core.type.DataTypes; 15 | import com.datastax.oss.driver.api.querybuilder.SchemaBuilder; 16 | import com.datastax.sample.model.TodoAppSchema; 17 | 18 | @RunWith(JUnitPlatform.class) 19 | public class CreateSchemaInAstraTest implements TodoAppSchema { 20 | 21 | /** Logger for the class. */ 22 | private static Logger LOGGER = LoggerFactory.getLogger(CreateSchemaInAstraTest.class); 23 | 24 | @Test 25 | public void should_create_expected_table() { 26 | 27 | // Config loader from file 28 | DriverConfigLoader loader = DriverConfigLoader.fromFile( 29 | new File(CreateSchemaInAstraTest.class.getResource("/application_test.conf").getFile())); 30 | 31 | // Use it to create the session 32 | try (CqlSession cqlSession = CqlSession.builder().withConfigLoader(loader).build()) { 33 | 34 | LOGGER.info("Connection Established to Astra with Keyspace '{}'", 35 | cqlSession.getKeyspace().get()); 36 | 37 | // Given a statement 38 | SimpleStatement stmtCreateTable = SchemaBuilder.createTable(TABLE_TODO_TASKS).ifNotExists() 39 | .withPartitionKey(TASK_COL_UID, DataTypes.UUID) 40 | .withColumn(TASK_COL_TITLE, DataTypes.TEXT) 41 | .withColumn(TASK_COL_COMPLETED, DataTypes.BOOLEAN) 42 | .withColumn(TASK_COL_OFFSET, DataTypes.INT) 43 | .build(); 44 | 45 | // When creating the table 46 | cqlSession.execute(stmtCreateTable); 47 | 48 | // Then table is created 49 | LOGGER.info("Table '{}' has been created (if needed).", TABLE_TODO_TASKS); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/test/java/com/datastax/samples/astra/CrudWithCassandraDriverIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.datastax.samples.astra; 2 | 3 | import java.io.File; 4 | import java.util.UUID; 5 | 6 | import javax.annotation.PreDestroy; 7 | 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.platform.runner.JUnitPlatform; 11 | import org.junit.runner.RunWith; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.boot.test.context.TestConfiguration; 16 | import org.springframework.context.annotation.Bean; 17 | import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; 18 | 19 | import com.datastax.oss.driver.api.core.CqlSession; 20 | import com.datastax.oss.driver.api.core.config.DriverConfigLoader; 21 | import com.datastax.oss.driver.api.core.cql.SimpleStatement; 22 | import com.datastax.oss.driver.api.core.cql.SimpleStatementBuilder; 23 | import com.datastax.oss.driver.api.querybuilder.QueryBuilder; 24 | import com.datastax.sample.model.Task; 25 | import com.datastax.sample.model.TodoAppSchema; 26 | import com.datastax.sample.repository.TodoListRepository; 27 | import com.datastax.sample.repository.TodoListRepositoryCassandraDriverImpl; 28 | 29 | /** 30 | * Junit5 + Spring. 31 | * @author Cedrick LUNVEN (@clunven) 32 | */ 33 | @RunWith(JUnitPlatform.class) 34 | @SpringJUnitConfig 35 | public class CrudWithCassandraDriverIntegrationTest implements TodoAppSchema { 36 | 37 | /** Logger for the class. */ 38 | private static Logger LOGGER = 39 | LoggerFactory.getLogger(CrudWithCassandraDriverIntegrationTest.class); 40 | 41 | @TestConfiguration 42 | static class CrudWithCassandraDriverConfiguration { 43 | 44 | @Bean 45 | public CqlSession cqlSession() { 46 | String configFile = CrudWithCassandraDriverIntegrationTest.class.getResource("/application_test.conf").getFile(); 47 | DriverConfigLoader configLoader = DriverConfigLoader.fromFile(new File(configFile)); 48 | return CqlSession.builder().withConfigLoader(configLoader).build(); 49 | } 50 | 51 | @Bean 52 | public TodoListRepository initRepo(CqlSession cqlSession) { 53 | TodoListRepositoryCassandraDriverImpl repo = new TodoListRepositoryCassandraDriverImpl(cqlSession); 54 | repo.initStatements(); 55 | return repo; 56 | } 57 | } 58 | 59 | @Autowired 60 | private CqlSession cqlSession; 61 | 62 | @Autowired 63 | private TodoListRepository todoRepo; 64 | 65 | /** 66 | * FIX THE TEST 67 | */ 68 | @Test 69 | public void test_Insert() { 70 | /* 71 | * ========================================== 72 | * Table Schema: 73 | * ========================================== 74 | * CREATE TABLE todoapp.todo_tasks ( 75 | * uid uuid, 76 | * completed boolean, 77 | * offset int, 78 | * title text, 79 | * PRIMARY KEY (uid) 80 | * ); 81 | * 82 | * ========================================== 83 | * Sample INSERT: 84 | * ========================================== 85 | * INSERT into todo_tasks(uid, title, offset, completed) 86 | * VALUES (uuid(), 'One', 1, true); 87 | */ 88 | 89 | // Using CqlSession and SimpleStatement insert this is table todo_tasks 90 | UUID sampleUID = UUID.randomUUID(); 91 | System.out.println(sampleUID); 92 | String sampleTitle = "A TASK"; 93 | int sampleOrder = 1; 94 | boolean sampleComplete = true; 95 | 96 | // Create here your statement and execute it 97 | //QueryBuilder.insertInto("todo_tasks").value(COL, value) 98 | SimpleStatement stmt = SimpleStatement.builder("" 99 | + "INSERT INTO todo_tasks (uid, title, offset, completed) " 100 | + "VALUES (?,?,?,?)") 101 | .addPositionalValue(sampleUID) 102 | .addPositionalValue(sampleTitle) 103 | .addPositionalValue(sampleOrder) 104 | .addPositionalValue(sampleComplete). 105 | build(); 106 | cqlSession.execute(stmt); 107 | 108 | //SimpleStatement stmtInsertTask = SimpleStatement.builder(.sampleTitle... 109 | Assertions.assertFalse(todoRepo.findById(sampleUID).isEmpty()); 110 | } 111 | 112 | @Test 113 | public void should_create_task_with_new_uid() { 114 | LOGGER.info("Starting CRUD Test"); 115 | // Given an empty table 116 | UUID newUid = UUID.randomUUID(); 117 | todoRepo.deleteAll(); 118 | Assertions.assertEquals(0, todoRepo.findAll().size()); 119 | LOGGER.info("+ Table has been empty"); 120 | 121 | // When adding a new Task 122 | todoRepo.upsert(new Task(newUid, "CrudWithCassandraDriverIntegrationTest", false, 1)); 123 | // Then you should have a table of size 1 124 | Assertions.assertEquals(1, todoRepo.findAll().size()); 125 | LOGGER.info("+ a New Task {} has been created", newUid); 126 | 127 | // Then you can find this task 128 | Assertions.assertFalse(todoRepo.findById(newUid).isEmpty()); 129 | LOGGER.info("+ And I can retrieve it", newUid); 130 | // And WHEN you delete it 131 | todoRepo.delete(newUid); 132 | // Then this is empty again 133 | Assertions.assertEquals(0, todoRepo.findAll().size()); 134 | LOGGER.info("+ And now this is removed", newUid); 135 | } 136 | 137 | @PreDestroy 138 | public void closeSession() { 139 | if (null != cqlSession) { 140 | cqlSession.close(); 141 | } 142 | } 143 | 144 | 145 | 146 | // SOLUTION of 5.c 147 | /* 148 | SimpleStatement stmtInsertTask = SimpleStatement.builder("" 149 | + "INSERT INTO todo_tasks(uid, title, offset, completed)" 150 | + "VALUES (?, ?, ?, ?)") 151 | .addPositionalValue(sampleUID) 152 | .addPositionalValue(sampleTitle) 153 | .addPositionalValue(sampleOrder) 154 | .addPositionalValue(sampleComplete) 155 | .build(); 156 | cqlSession.execute(stmtInsertTask); 157 | */ 158 | 159 | 160 | } 161 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/test/java/com/datastax/samples/astra/CrudWithObjectMapperTest.java: -------------------------------------------------------------------------------- 1 | package com.datastax.samples.astra; 2 | 3 | import java.io.File; 4 | import java.util.UUID; 5 | 6 | import javax.annotation.PreDestroy; 7 | 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.platform.runner.JUnitPlatform; 11 | import org.junit.runner.RunWith; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.boot.test.context.TestConfiguration; 16 | import org.springframework.context.annotation.Bean; 17 | import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; 18 | 19 | import com.datastax.oss.driver.api.core.CqlSession; 20 | import com.datastax.oss.driver.api.core.config.DriverConfigLoader; 21 | import com.datastax.sample.model.Task; 22 | import com.datastax.sample.repository.TodoListRepository; 23 | import com.datastax.sample.repository.TodoListRepositoryObjectMapperImpl; 24 | 25 | /** 26 | * Test CRUD with ObjectMapper 27 | * 28 | * @author Cedrick LUNVEN (@clunven) 29 | */ 30 | @RunWith(JUnitPlatform.class) 31 | @SpringJUnitConfig 32 | public class CrudWithObjectMapperTest { 33 | 34 | /** Logger for the class. */ 35 | private static Logger LOGGER = LoggerFactory.getLogger(CrudWithObjectMapperTest.class); 36 | 37 | @TestConfiguration 38 | static class MyTestConfiguration { 39 | 40 | @Bean 41 | public CqlSession cqlSession() { 42 | String configFile = CrudWithCassandraDriverIntegrationTest.class.getResource("/application_test.conf").getFile(); 43 | DriverConfigLoader configLoader = DriverConfigLoader.fromFile(new File(configFile)); 44 | return CqlSession.builder().withConfigLoader(configLoader).build(); 45 | } 46 | 47 | @Bean 48 | public TodoListRepository initRepo(CqlSession cqlSession) { 49 | return new TodoListRepositoryObjectMapperImpl(cqlSession); 50 | } 51 | } 52 | 53 | @Autowired 54 | private CqlSession cqlSession; 55 | 56 | @Autowired 57 | private TodoListRepository todoRepo; 58 | 59 | @Test 60 | public void should_all_crud() { 61 | LOGGER.info("Starting CRUD Test"); 62 | // Given an empty table 63 | UUID newUid = UUID.randomUUID(); 64 | todoRepo.deleteAll(); 65 | Assertions.assertEquals(0, todoRepo.findAll().size()); 66 | LOGGER.info("+ Table has been empty"); 67 | 68 | // When adding a new Task 69 | todoRepo.upsert(new Task(newUid, "CrudWithCassandraDriverIntegrationTest", false, 1)); 70 | // Then you should have a table of size 1 71 | Assertions.assertEquals(1, todoRepo.findAll().size()); 72 | LOGGER.info("+ a New Task {} has been created", newUid); 73 | 74 | // Then you can find this task 75 | Assertions.assertFalse(todoRepo.findById(newUid).isEmpty()); 76 | LOGGER.info("+ And I can retrieve it", newUid); 77 | // And WHEN you delete it 78 | todoRepo.delete(newUid); 79 | // Then this is empty again 80 | Assertions.assertEquals(0, todoRepo.findAll().size()); 81 | LOGGER.info("+ And now this is removed", newUid); 82 | } 83 | 84 | @PreDestroy 85 | public void closeSession() { 86 | if (null != cqlSession) { 87 | cqlSession.close(); 88 | } 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /todobackend-cassandra/src/test/resources/application_test.conf: -------------------------------------------------------------------------------- 1 | datastax-java-driver { 2 | 3 | basic { 4 | request { 5 | timeout = 8 seconds 6 | consistency = LOCAL_QUORUM 7 | page-size = 5000 8 | } 9 | session-keyspace = todoapp 10 | cloud { 11 | secure-connect-bundle = /Users/cedricklunven/Downloads/secure-connect-dev-workshop-db.zip 12 | } 13 | } 14 | 15 | advanced { 16 | auth-provider { 17 | class = PlainTextAuthProvider 18 | username = todouser 19 | password = todopassword 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /todobackend-cassandra/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} %magenta(%-5level) %cyan(%-45logger) : %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /z-materials/images/astra-create-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/astra-create-2.png -------------------------------------------------------------------------------- /z-materials/images/astra-create-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/astra-create-3.png -------------------------------------------------------------------------------- /z-materials/images/astra-create-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/astra-create-4.png -------------------------------------------------------------------------------- /z-materials/images/astra-create-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/astra-create-5.png -------------------------------------------------------------------------------- /z-materials/images/astra-create-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/astra-create-6.png -------------------------------------------------------------------------------- /z-materials/images/astra-create-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/astra-create-7.png -------------------------------------------------------------------------------- /z-materials/images/astra-create-login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/astra-create-login.png -------------------------------------------------------------------------------- /z-materials/images/astra-create-register.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/astra-create-register.png -------------------------------------------------------------------------------- /z-materials/images/backend-doc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/backend-doc.png -------------------------------------------------------------------------------- /z-materials/images/backend-ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/backend-ok.png -------------------------------------------------------------------------------- /z-materials/images/describe-output-cqlconsole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/describe-output-cqlconsole.png -------------------------------------------------------------------------------- /z-materials/images/describe-output-studio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/describe-output-studio.png -------------------------------------------------------------------------------- /z-materials/images/gitpod-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/gitpod-home.png -------------------------------------------------------------------------------- /z-materials/images/gitpod-updated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/gitpod-updated.png -------------------------------------------------------------------------------- /z-materials/images/gitpod-upload-files.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/gitpod-upload-files.png -------------------------------------------------------------------------------- /z-materials/images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/home.png -------------------------------------------------------------------------------- /z-materials/images/import-project-eclipse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/import-project-eclipse.png -------------------------------------------------------------------------------- /z-materials/images/intellij-import-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/intellij-import-1.png -------------------------------------------------------------------------------- /z-materials/images/intellij-import-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/intellij-import-2.png -------------------------------------------------------------------------------- /z-materials/images/launch-studio-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/launch-studio-home.png -------------------------------------------------------------------------------- /z-materials/images/launch-studio-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/launch-studio-import.png -------------------------------------------------------------------------------- /z-materials/images/launch-studio-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/launch-studio-open.png -------------------------------------------------------------------------------- /z-materials/images/launch-studio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/launch-studio.png -------------------------------------------------------------------------------- /z-materials/images/linux32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/linux32.png -------------------------------------------------------------------------------- /z-materials/images/locate-cqlconsole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/locate-cqlconsole.png -------------------------------------------------------------------------------- /z-materials/images/locate-studio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/locate-studio.png -------------------------------------------------------------------------------- /z-materials/images/mac32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/mac32.png -------------------------------------------------------------------------------- /z-materials/images/realbackend-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/realbackend-test.png -------------------------------------------------------------------------------- /z-materials/images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/splash.png -------------------------------------------------------------------------------- /z-materials/images/todobackend-output-client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/todobackend-output-client.png -------------------------------------------------------------------------------- /z-materials/images/todobackend-output-host.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/todobackend-output-host.png -------------------------------------------------------------------------------- /z-materials/images/todobackend-runclient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/todobackend-runclient.png -------------------------------------------------------------------------------- /z-materials/images/todobackend-runtest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/todobackend-runtest.png -------------------------------------------------------------------------------- /z-materials/images/todobackend-swagger-test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/todobackend-swagger-test.png -------------------------------------------------------------------------------- /z-materials/images/todobackend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/todobackend.png -------------------------------------------------------------------------------- /z-materials/images/todomvc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/todomvc.png -------------------------------------------------------------------------------- /z-materials/images/welldone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/welldone.jpg -------------------------------------------------------------------------------- /z-materials/images/windows32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/images/windows32.png -------------------------------------------------------------------------------- /z-materials/notebooks/datastax-studio-notebook.tar: -------------------------------------------------------------------------------- 1 | notebook.bin0100644 0000000 0000000 00000003613 13672105550 012126 0ustar000000000 0000000 json_notebook_v1{"1":"4ed1bbec-f95f-44a0-904d-adcf56e6e43c","10":"67257e07-1c1b-41e0-9709-fbcd348c2813","11":"Build Java Microservice with Cassandra","12":{"1":1592088523,"2":540000000},"13":{"1":1592294979,"2":860000000},"14":false,"15":[{"1":"3a8ae75d-50fa-4735-818a-fd8787549420","10":4,"11":"![SplashScreen](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/splash.png?raw=true)","12":"markdown","13":{"1":"4089bc6c-609c-4a6b-900e-51b5915dd03e","10":{"9":"

\"SplashScreen\"

\n"},"11":4,"12":false},"16":true,"17":true,"18":{},"23":79,"24":"todoapp","25":"LOCAL.QUORUM"},{"1":"b84aab44-2c2a-4839-913f-448397e92048","11":"insert into todo_tasks(uid, title, offset, completed) VALUES (uuid(), 'One', 1, true);\ninsert into todo_tasks(uid, title, offset, completed) VALUES (uuid(), 'Two', 2, true);\ninsert into todo_tasks(uid, title, offset, completed) VALUES (uuid(), 'Three', 3, true);\n","12":"cql","16":true,"17":false,"18":{},"22":112,"24":"todoapp","25":"LOCAL.QUORUM"},{"1":"61e36411-e69e-47b1-b14c-6498d23438e6","11":"select * from todo_tasks;","12":"cql","16":true,"17":false,"24":"todoapp","25":"LOCAL.QUORUM"},{"1":"058526ca-2ffd-4c64-b4a0-93663738c0f4","11":"SELECT * FROM todo_tasks where uid= d1d19715-a397-4975-bcb3-5107712db387;","12":"cql","16":true,"17":false,"24":"todoapp","25":"LOCAL.QUORUM"},{"1":"e9621215-9280-485e-8db1-e5fccedadb0a","11":"DELETE FROM todo_tasks where uid= d1d19715-a397-4975-bcb3-5107712db387;","12":"cql","16":true,"17":false,"23":65,"24":"todoapp","25":"LOCAL.QUORUM"}],"16":{"1":{}},"17":"","19":false}code.txt0100644 0000000 0000000 00000001633 13672105550 011267 0ustar000000000 0000000 --------------------NOTEBOOK_Build Java Microservice with Cassandra-------------------- 2 | --------------------CELL_MARKDOWN_1-------------------- 3 | ![SplashScreen](https://github.com/DataStax-Academy/microservices-java-workshop-online/blob/master/z-materials/images/splash.png?raw=true) 4 | --------------------CELL_CQL_2-------------------- 5 | insert into todo_tasks(uid, title, offset, completed) VALUES (uuid(), 'One', 1, true); 6 | insert into todo_tasks(uid, title, offset, completed) VALUES (uuid(), 'Two', 2, true); 7 | insert into todo_tasks(uid, title, offset, completed) VALUES (uuid(), 'Three', 3, true); 8 | 9 | --------------------CELL_CQL_3-------------------- 10 | select * from todo_tasks; 11 | --------------------CELL_CQL_4-------------------- 12 | SELECT * FROM todo_tasks where uid= d1d19715-a397-4975-bcb3-5107712db387; 13 | --------------------CELL_CQL_5-------------------- 14 | DELETE FROM todo_tasks where uid= d1d19715-a397-4975-bcb3-5107712db387; 15 | versions-info.txt0100644 0000000 0000000 00000000036 13672105550 013152 0ustar000000000 0000000 Studio Version: 6.8.0-bb55f0c 16 | -------------------------------------------------------------------------------- /z-materials/presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-microservices-java/9d6366d8843526d2d57739d122b388c2d876aa9b/z-materials/presentation.pdf --------------------------------------------------------------------------------