-
Notifications
You must be signed in to change notification settings - Fork 5
/
DSE_Application_Development_Prepared_Statements.studio-nb.tar
233 lines (177 loc) · 40 KB
/
DSE_Application_Development_Prepared_Statements.studio-nb.tar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
notebook.bin 0100644 0000000 0000000 00000056765 13355211672 012147 0 ustar 00 0000000 0000000 json_notebook_v1 {"1":"bed65194-59a9-457f-b98f-849c2fd1df2c","10":"e3111e9b-0a01-4111-a584-a2ab859e15c6","11":"DSE Application Development: Prepared Statements","12":{"1":1538470281,"2":520000000},"13":{"1":1538590698,"2":587000000},"14":false,"15":[{"1":"d5ebd65b-2806-4610-b016-02efe406426b","10":4,"11":"<center>![Solution Day Banner](https://s3.amazonaws.com/datastaxtraining/solution-days/cassandra-intro/DevDayBanner.png \"Developer Day Banner\" )</center>","12":"markdown","13":{"1":"1cb5fe7f-537f-4aa8-8dfc-4a7971ad04ea","10":{"9":"<p><center><img src=\"https://s3.amazonaws.com/datastaxtraining/solution-days/cassandra-intro/DevDayBanner.png\" alt=\"Solution Day Banner\" title=\"Developer Day Banner\" /></center></p>\n"},"11":4,"12":false},"15":5,"16":true,"17":true,"18":{},"25":"CL.ONE"},{"1":"b86ebb37-b7e9-49a2-a510-938aa4779466","10":4,"11":"In this exercise, you will add the code to the KillrVideo application to insert a new user. First, open your web-based Eclipse editor by visiting the url: `http://<your-che-node-IP-address>:8080/dashboard/#/ide/che/killrvideo`.\n\n![Eclipse Che](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/eclipse-che.png \"Eclipse Che\" )","12":"markdown","13":{"1":"1404bebc-2d5e-4032-8a27-9f1ceb445035","10":{"9":"<p>In this exercise, you will add the code to the KillrVideo application to insert a new user. First, open your web-based Eclipse editor by visiting the url: <code>http://<your-che-node-IP-address>:8080/dashboard/#/ide/che/killrvideo</code>.</p>\n<p><img src=\"https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/eclipse-che.png\" alt=\"Eclipse Che\" title=\"Eclipse Che\" /></p>\n"},"11":4,"12":false},"16":true,"17":true,"18":{},"25":"CL.ONE"},{"1":"bf3f3bb8-70cc-4087-a259-001a2db05fb7","10":4,"11":"Run the application by pressing the blue execute arrow at the top or by using the keyboard shortcut `ALT-R` (or `COMMAND-R` on Mac).\n\n<center>![Starting the Application](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/start-application.PNG \"Starting the Application\" )</center>\n\nOnce the application is running, navigate to `http://<your-web-node-ip-address>:3000`, and notice the webpage loads.\n\n<center>![KillrVideo Page](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/killrvideo-page.PNG \"KillrVideo Page\" )</center>\n\nGo ahead and follow the steps to create a new user by clicking on the green `REGISTER` button to the upper right.\n\n<center>![Register Button](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/register-button.PNG \"Register Button\" )</center>\n\n<center>![Registration Info](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/registration-info.PNG \"Registration Info\" )</center>\n\nNotice the registration is broken, and the button just hangs indefinitely. WAH WAHHHH.\n\n<center>![Busted Regisration](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/busted-registratation.PNG \"Busted Registration\" )</center>","12":"markdown","13":{"1":"ffcdca43-320a-4921-a3bb-817a071bd885","10":{"9":"<p>Run the application by pressing the blue execute arrow at the top or by using the keyboard shortcut <code>ALT-R</code> (or <code>COMMAND-R</code> on Mac).</p>\n<p><center><img src=\"https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/start-application.PNG\" alt=\"Starting the Application\" title=\"Starting the Application\" /></center></p>\n<p>Once the application is running, navigate to <code>http://<your-web-node-ip-address>:3000</code>, and notice the webpage loads.</p>\n<p><center><img src=\"https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/killrvideo-page.PNG\" alt=\"KillrVideo Page\" title=\"KillrVideo Page\" /></center></p>\n<p>Go ahead and follow the steps to create a new user by clicking on the green <code>REGISTER</code> button to the upper right.</p>\n<p><center><img src=\"https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/register-button.PNG\" alt=\"Register Button\" title=\"Register Button\" /></center></p>\n<p><center><img src=\"https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/registration-info.PNG\" alt=\"Registration Info\" title=\"Registration Info\" /></center></p>\n<p>Notice the registration is broken, and the button just hangs indefinitely. WAH WAHHHH.</p>\n<p><center><img src=\"https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/busted-registratation.PNG\" alt=\"Busted Regisration\" title=\"Busted Registration\" /></center></p>\n"},"11":4,"12":false},"16":true,"17":true,"18":{},"25":"CL.ONE"},{"1":"95d94daf-f2fc-47af-814e-4bebcd3d316a","10":4,"11":"Your mission, should you choose to accept it, is to make the user sign-on process work. No stress. We will take you through it. First off, in your Eclipse Che `killrvideo` workspace, navigate to and open the file `/killrvideo-java/src/main/java/killrvideo/service/UserManagementService.java`.\n\n<center>![User Management Service File](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/user-management-service.PNG \"User Management Service File\" )</center>\n\nFind the following comment:\n\n```\n // DECLARE THOSE FIELDS!\n```\n\nThe first fields we will declare are two prepared statments:\n\n1) Check that a user email doesn't already exist in the `user_credentials` table.\n2) Insert the full user information into the `users` table.\n\nCopy the following lines of code and paste them over the comment:\n\n```\n private PreparedStatement createUser_checkEmailPrepared;\n private PreparedStatement createUser_insertUserPrepared;\n```\n\nNotice both are a `PreparedStatement` which means the cluster will compile the statement distribute the statement once, and we can fill in the variables later. `PreparedStatements` are faster this way over using `SimpleStatements` which must compile and distribute the query every time.","12":"markdown","13":{"1":"16492075-d537-4a77-8a46-39a24cf2001a","10":{"9":"<p>Your mission, should you choose to accept it, is to make the user sign-on process work. No stress. We will take you through it. First off, in your Eclipse Che <code>killrvideo</code> workspace, navigate to and open the file <code>/killrvideo-java/src/main/java/killrvideo/service/UserManagementService.java</code>.</p>\n<p><center><img src=\"https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/user-management-service.PNG\" alt=\"User Management Service File\" title=\"User Management Service File\" /></center></p>\n<p>Find the following comment:</p>\n<pre><code> // DECLARE THOSE FIELDS!\n</code></pre>\n<p>The first fields we will declare are two prepared statments:</p>\n<p>1) Check that a user email doesn't already exist in the <code>user_credentials</code> table.\n<br />2) Insert the full user information into the <code>users</code> table.</p>\n<p>Copy the following lines of code and paste them over the comment:</p>\n<pre><code> private PreparedStatement createUser_checkEmailPrepared;\n private PreparedStatement createUser_insertUserPrepared;\n</code></pre>\n<p>Notice both are a <code>PreparedStatement</code> which means the cluster will compile the statement distribute the statement once, and we can fill in the variables later. <code>PreparedStatements</code> are faster this way over using <code>SimpleStatements</code> which must compile and distribute the query every time.</p>\n"},"11":4,"12":false},"16":true,"17":true,"18":{},"25":"CL.ONE"},{"1":"8a20b032-3aa9-4d80-a5d4-3dc2e18c0d2b","10":4,"11":"Now find the following comment in the same file:\n\n```\n // PREPARE THOSE STATEMENTS!\n```\n\nand replace it with the following code:\n\n```\n createUser_checkEmailPrepared = dseSession.prepare(\n QueryBuilder\n .insertInto(Schema.KEYSPACE, userCredentialsTableName)\n .value(\"email\", QueryBuilder.bindMarker())\n .value(\"password\", QueryBuilder.bindMarker())\n .value(\"userid\", QueryBuilder.bindMarker())\n .ifNotExists() // use lightweight transaction\n ).setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM);\n\n createUser_insertUserPrepared = dseSession.prepare(\n QueryBuilder\n .insertInto(Schema.KEYSPACE, usersTableName)\n .value(\"userid\", QueryBuilder.bindMarker())\n .value(\"firstname\", QueryBuilder.bindMarker())\n .value(\"lastname\", QueryBuilder.bindMarker())\n .value(\"email\", QueryBuilder.bindMarker())\n .value(\"created_date\", QueryBuilder.bindMarker())\n .ifNotExists() // use lightweight transaction\n ).setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM);\n```\n\nNotice we use `QueryBuilder` to draft up our query, placing `bindMarker()`s where the insert variables will later go. We also set the consistency level on both queries and a lightweight transaction to avoid duplicate users. `dseSession.prepare()` is where the compile-once-and-reuse magic happens. All we need to do now is `bind()` our prepared statement variables to actual values and `execute()` the result.","12":"markdown","13":{"1":"98a9f911-39db-48fe-b7e2-2944926fee47","10":{"9":"<p>Now find the following comment in the same file:</p>\n<pre><code> // PREPARE THOSE STATEMENTS!\n</code></pre>\n<p>and replace it with the following code:</p>\n<pre><code> createUser_checkEmailPrepared = dseSession.prepare(\n QueryBuilder\n .insertInto(Schema.KEYSPACE, userCredentialsTableName)\n .value(\"email\", QueryBuilder.bindMarker())\n .value(\"password\", QueryBuilder.bindMarker())\n .value(\"userid\", QueryBuilder.bindMarker())\n .ifNotExists() // use lightweight transaction\n ).setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM);\n\n createUser_insertUserPrepared = dseSession.prepare(\n QueryBuilder\n .insertInto(Schema.KEYSPACE, usersTableName)\n .value(\"userid\", QueryBuilder.bindMarker())\n .value(\"firstname\", QueryBuilder.bindMarker())\n .value(\"lastname\", QueryBuilder.bindMarker())\n .value(\"email\", QueryBuilder.bindMarker())\n .value(\"created_date\", QueryBuilder.bindMarker())\n .ifNotExists() // use lightweight transaction\n ).setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM);\n</code></pre>\n<p>Notice we use <code>QueryBuilder</code> to draft up our query, placing <code>bindMarker()</code>s where the insert variables will later go. We also set the consistency level on both queries and a lightweight transaction to avoid duplicate users. <code>dseSession.prepare()</code> is where the compile-once-and-reuse magic happens. All we need to do now is <code>bind()</code> our prepared statement variables to actual values and <code>execute()</code> the result.</p>\n"},"11":4,"12":false},"16":true,"17":true,"18":{},"25":"CL.ONE"},{"1":"82066d68-5024-401f-8788-0e02d6c5c5a7","10":4,"11":"Now find the following comment within that same file:\n\n```\n // CREATE THAT USER!\n```\n\nHere we will bind our variables and execute our insert.\n\nPaste the following code over that comment:\n\n```\n if (!validator.isValid(request, responseObserver)) {\n return;\n }\n\n```\n\nThis simply validates that the HTTP request is valid. Now add the following code below that:\n\n```\n final Date now = new Date();\n final CommonTypes.Uuid userIdUuid = request.getUserId();\n final UUID userIdUUID = UUID.fromString(userIdUuid.getValue());\n final String firstName = request.getFirstName();\n final String lastName = request.getLastName();\n\n final String hashedPassword = HashUtils.hashPassword(request.getPassword().trim());\n final String email = request.getEmail();\n final String dupUserMessaage = String.format(\"Exception creating user because it already exists with email %s\", email);\n```\nThis pulls the values we are interested out of the HTTP request.\n\nNow add the following:\n\n```\n final BoundStatement checkEmailQuery = createUser_checkEmailPrepared.bind()\n .setString(\"email\", email)\n .setString(\"password\", hashedPassword)\n .setUUID(\"userid\", userIdUUID);\n```\nThis binds our `createUser_checkEmailPrepared` prepared statment to actual values, making a `BoundStatement` that we can actually `execute()`.\n\nContinue adding:\n\n```\n ResultSet checkEmailResultSet = dseSession.execute(checkEmailQuery);\n if (!checkEmailResultSet.wasApplied()) {\n responseObserver.onError(Status.INVALID_ARGUMENT\n .augmentDescription(dupUserMessaage).asRuntimeException());\n responseObserver.onCompleted();\n return;\n }\n```\n\nHere we `execute()` our `BoundStatment` and further check that the insert `wasApplied()`. If not, we return an error.\n\nContinue adding code:\n```\n final BoundStatement insertUser = createUser_insertUserPrepared.bind()\n .setUUID(\"userid\", userIdUUID)\n .setString(\"firstname\", firstName)\n .setString(\"lastname\", lastName)\n .setString(\"email\", email)\n .setTimestamp(\"created_date\", now);\n\n ResultSet insertUserResultSet = dseSession.execute(insertUser);\n\n if(!insertUserResultSet.wasApplied()) {\n responseObserver.onError(Status.INVALID_ARGUMENT\n .augmentDescription(\"User ID not unique\").asRuntimeException());\n responseObserver.onCompleted();\n return;\n }\n\n```\nThis inserts the full user record into the `users` table. Again we check that the result applied.\n\nNow finish serving the HTTP request by adding the following:\n\n```\n responseObserver.onNext(CreateUserResponse.newBuilder().build());\n responseObserver.onCompleted();\n```","12":"markdown","13":{"1":"f9c071af-a409-451d-ace8-4946bdefd33f","10":{"9":"<p>Now find the following comment within that same file:</p>\n<pre><code> // CREATE THAT USER!\n</code></pre>\n<p>Here we will bind our variables and execute our insert.</p>\n<p>Paste the following code over that comment:</p>\n<pre><code> if (!validator.isValid(request, responseObserver)) {\n return;\n }\n</code></pre>\n<p>This simply validates that the HTTP request is valid. Now add the following code below that:</p>\n<pre><code> final Date now = new Date();\n final CommonTypes.Uuid userIdUuid = request.getUserId();\n final UUID userIdUUID = UUID.fromString(userIdUuid.getValue());\n final String firstName = request.getFirstName();\n final String lastName = request.getLastName();\n\n final String hashedPassword = HashUtils.hashPassword(request.getPassword().trim());\n final String email = request.getEmail();\n final String dupUserMessaage = String.format(\"Exception creating user because it already exists with email %s\", email);\n</code></pre>\n<p>This pulls the values we are interested out of the HTTP request.</p>\n<p>Now add the following:</p>\n<pre><code> final BoundStatement checkEmailQuery = createUser_checkEmailPrepared.bind()\n .setString(\"email\", email)\n .setString(\"password\", hashedPassword)\n .setUUID(\"userid\", userIdUUID);\n</code></pre>\n<p>This binds our <code>createUser_checkEmailPrepared</code> prepared statment to actual values, making a <code>BoundStatement</code> that we can actually <code>execute()</code>.</p>\n<p>Continue adding:</p>\n<pre><code> ResultSet checkEmailResultSet = dseSession.execute(checkEmailQuery);\n if (!checkEmailResultSet.wasApplied()) {\n responseObserver.onError(Status.INVALID_ARGUMENT\n .augmentDescription(dupUserMessaage).asRuntimeException());\n responseObserver.onCompleted();\n return;\n }\n</code></pre>\n<p>Here we <code>execute()</code> our <code>BoundStatment</code> and further check that the insert <code>wasApplied()</code>. If not, we return an error.</p>\n<p>Continue adding code:</p>\n<pre><code> final BoundStatement insertUser = createUser_insertUserPrepared.bind()\n .setUUID(\"userid\", userIdUUID)\n .setString(\"firstname\", firstName)\n .setString(\"lastname\", lastName)\n .setString(\"email\", email)\n .setTimestamp(\"created_date\", now);\n\n ResultSet insertUserResultSet = dseSession.execute(insertUser);\n\n if(!insertUserResultSet.wasApplied()) {\n responseObserver.onError(Status.INVALID_ARGUMENT\n .augmentDescription(\"User ID not unique\").asRuntimeException());\n responseObserver.onCompleted();\n return;\n }\n</code></pre>\n<p>This inserts the full user record into the <code>users</code> table. Again we check that the result applied.</p>\n<p>Now finish serving the HTTP request by adding the following:</p>\n<pre><code> responseObserver.onNext(CreateUserResponse.newBuilder().build());\n responseObserver.onCompleted();\n</code></pre>\n"},"11":4,"12":false},"16":true,"17":true,"18":{},"25":"CL.ONE"},{"1":"2319163c-2ec5-4b2a-b1dc-6da93324e98d","10":4,"11":"The entire `createUser()` function should look like so:\n\n```\n@Override\npublic void createUser(CreateUserRequest request, StreamObserver<CreateUserResponse> responseObserver) {\n if (!validator.isValid(request, responseObserver)) {\n return;\n }\n\n final Date now = new Date();\n final CommonTypes.Uuid userIdUuid = request.getUserId();\n final UUID userIdUUID = UUID.fromString(userIdUuid.getValue());\n final String firstName = request.getFirstName();\n final String lastName = request.getLastName();\n\n final String hashedPassword = HashUtils.hashPassword(request.getPassword().trim());\n final String email = request.getEmail();\n final String dupUserMessaage = String.format(\"Exception creating user because it already exists with email %s\", email);\n\n final BoundStatement checkEmailQuery = createUser_checkEmailPrepared.bind()\n .setString(\"email\", email)\n .setString(\"password\", hashedPassword)\n .setUUID(\"userid\", userIdUUID);\n\n ResultSet checkEmailResultSet = dseSession.execute(checkEmailQuery);\n if (!checkEmailResultSet.wasApplied()) {\n responseObserver.onError(Status.INVALID_ARGUMENT\n .augmentDescription(dupUserMessaage).asRuntimeException());\n responseObserver.onCompleted();\n return;\n }\n\n final BoundStatement insertUser = createUser_insertUserPrepared.bind()\n .setUUID(\"userid\", userIdUUID)\n .setString(\"firstname\", firstName)\n .setString(\"lastname\", lastName)\n .setString(\"email\", email)\n .setTimestamp(\"created_date\", now);\n\n ResultSet insertUserResultSet = dseSession.execute(insertUser);\n\n if(!insertUserResultSet.wasApplied()) {\n responseObserver.onError(Status.INVALID_ARGUMENT\n .augmentDescription(\"User ID not unique\").asRuntimeException());\n responseObserver.onCompleted();\n return;\n }\n\n responseObserver.onNext(CreateUserResponse.newBuilder().build());\n responseObserver.onCompleted();\n}\n\n```","12":"markdown","13":{"1":"585f7329-3382-4d12-a36d-df6ffdf360be","10":{"9":"<p>The entire <code>createUser()</code> function should look like so:</p>\n<pre><code>@Override\npublic void createUser(CreateUserRequest request, StreamObserver<CreateUserResponse> responseObserver) {\n if (!validator.isValid(request, responseObserver)) {\n return;\n }\n\n final Date now = new Date();\n final CommonTypes.Uuid userIdUuid = request.getUserId();\n final UUID userIdUUID = UUID.fromString(userIdUuid.getValue());\n final String firstName = request.getFirstName();\n final String lastName = request.getLastName();\n\n final String hashedPassword = HashUtils.hashPassword(request.getPassword().trim());\n final String email = request.getEmail();\n final String dupUserMessaage = String.format(\"Exception creating user because it already exists with email %s\", email);\n\n final BoundStatement checkEmailQuery = createUser_checkEmailPrepared.bind()\n .setString(\"email\", email)\n .setString(\"password\", hashedPassword)\n .setUUID(\"userid\", userIdUUID);\n\n ResultSet checkEmailResultSet = dseSession.execute(checkEmailQuery);\n if (!checkEmailResultSet.wasApplied()) {\n responseObserver.onError(Status.INVALID_ARGUMENT\n .augmentDescription(dupUserMessaage).asRuntimeException());\n responseObserver.onCompleted();\n return;\n }\n\n final BoundStatement insertUser = createUser_insertUserPrepared.bind()\n .setUUID(\"userid\", userIdUUID)\n .setString(\"firstname\", firstName)\n .setString(\"lastname\", lastName)\n .setString(\"email\", email)\n .setTimestamp(\"created_date\", now);\n\n ResultSet insertUserResultSet = dseSession.execute(insertUser);\n\n if(!insertUserResultSet.wasApplied()) {\n responseObserver.onError(Status.INVALID_ARGUMENT\n .augmentDescription(\"User ID not unique\").asRuntimeException());\n responseObserver.onCompleted();\n return;\n }\n\n responseObserver.onNext(CreateUserResponse.newBuilder().build());\n responseObserver.onCompleted();\n}\n</code></pre>\n"},"11":4,"12":false},"16":true,"17":true,"18":{},"25":"CL.ONE"},{"1":"822647fd-3697-43df-b733-4f5196bac664","10":4,"11":"Stop your previously running KillrVideo instance by clicking on the `X` under the `Machines` area towards the bottom of your Eclipse Che window.\n\n<center>![Close Application](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/close-appplication.PNG \"Close Application\" )</center>\n\nClick OK to confirm this action.\n\nThen re-run your application but using the `ALT-R` hot key.\n\nThen go ahead and re-register then sign in with the user information you registered on the site with earlier. If it works properly, the site will redirect you to the home page.\n\nYAY!","12":"markdown","13":{"1":"3986b718-ba55-4c6d-bdad-b489c9ffd0b5","10":{"9":"<p>Stop your previously running KillrVideo instance by clicking on the <code>X</code> under the <code>Machines</code> area towards the bottom of your Eclipse Che window.</p>\n<p><center><img src=\"https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/close-appplication.PNG\" alt=\"Close Application\" title=\"Close Application\" /></center></p>\n<p>Click OK to confirm this action.</p>\n<p>Then re-run your application but using the <code>ALT-R</code> hot key.</p>\n<p>Then go ahead and re-register then sign in with the user information you registered on the site with earlier. If it works properly, the site will redirect you to the home page.</p>\n<p>YAY!</p>\n"},"11":4,"12":false},"16":true,"17":true,"18":{},"25":"CL.ONE"}],"16":{"1":{}},"17":"KillrVideoGraph"} code.txt 0100644 0000000 0000000 00000025023 13355211672 011267 0 ustar 00 0000000 0000000 --------------------NOTEBOOK_DSE Application Development: Prepared Statements--------------------
--------------------CELL_MARKDOWN_1--------------------
<center>![Solution Day Banner](https://s3.amazonaws.com/datastaxtraining/solution-days/cassandra-intro/DevDayBanner.png "Developer Day Banner" )</center>
--------------------CELL_MARKDOWN_2--------------------
In this exercise, you will add the code to the KillrVideo application to insert a new user. First, open your web-based Eclipse editor by visiting the url: `http://<your-che-node-IP-address>:8080/dashboard/#/ide/che/killrvideo`.
![Eclipse Che](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/eclipse-che.png "Eclipse Che" )
--------------------CELL_MARKDOWN_3--------------------
Run the application by pressing the blue execute arrow at the top or by using the keyboard shortcut `ALT-R` (or `COMMAND-R` on Mac).
<center>![Starting the Application](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/start-application.PNG "Starting the Application" )</center>
Once the application is running, navigate to `http://<your-web-node-ip-address>:3000`, and notice the webpage loads.
<center>![KillrVideo Page](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/killrvideo-page.PNG "KillrVideo Page" )</center>
Go ahead and follow the steps to create a new user by clicking on the green `REGISTER` button to the upper right.
<center>![Register Button](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/register-button.PNG "Register Button" )</center>
<center>![Registration Info](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/registration-info.PNG "Registration Info" )</center>
Notice the registration is broken, and the button just hangs indefinitely. WAH WAHHHH.
<center>![Busted Regisration](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/busted-registratation.PNG "Busted Registration" )</center>
--------------------CELL_MARKDOWN_4--------------------
Your mission, should you choose to accept it, is to make the user sign-on process work. No stress. We will take you through it. First off, in your Eclipse Che `killrvideo` workspace, navigate to and open the file `/killrvideo-java/src/main/java/killrvideo/service/UserManagementService.java`.
<center>![User Management Service File](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/user-management-service.PNG "User Management Service File" )</center>
Find the following comment:
```
// DECLARE THOSE FIELDS!
```
The first fields we will declare are two prepared statments:
1) Check that a user email doesn't already exist in the `user_credentials` table.
2) Insert the full user information into the `users` table.
Copy the following lines of code and paste them over the comment:
```
private PreparedStatement createUser_checkEmailPrepared;
private PreparedStatement createUser_insertUserPrepared;
```
Notice both are a `PreparedStatement` which means the cluster will compile the statement distribute the statement once, and we can fill in the variables later. `PreparedStatements` are faster this way over using `SimpleStatements` which must compile and distribute the query every time.
--------------------CELL_MARKDOWN_5--------------------
Now find the following comment in the same file:
```
// PREPARE THOSE STATEMENTS!
```
and replace it with the following code:
```
createUser_checkEmailPrepared = dseSession.prepare(
QueryBuilder
.insertInto(Schema.KEYSPACE, userCredentialsTableName)
.value("email", QueryBuilder.bindMarker())
.value("password", QueryBuilder.bindMarker())
.value("userid", QueryBuilder.bindMarker())
.ifNotExists() // use lightweight transaction
).setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM);
createUser_insertUserPrepared = dseSession.prepare(
QueryBuilder
.insertInto(Schema.KEYSPACE, usersTableName)
.value("userid", QueryBuilder.bindMarker())
.value("firstname", QueryBuilder.bindMarker())
.value("lastname", QueryBuilder.bindMarker())
.value("email", QueryBuilder.bindMarker())
.value("created_date", QueryBuilder.bindMarker())
.ifNotExists() // use lightweight transaction
).setConsistencyLevel(ConsistencyLevel.LOCAL_QUORUM);
```
Notice we use `QueryBuilder` to draft up our query, placing `bindMarker()`s where the insert variables will later go. We also set the consistency level on both queries and a lightweight transaction to avoid duplicate users. `dseSession.prepare()` is where the compile-once-and-reuse magic happens. All we need to do now is `bind()` our prepared statement variables to actual values and `execute()` the result.
--------------------CELL_MARKDOWN_6--------------------
Now find the following comment within that same file:
```
// CREATE THAT USER!
```
Here we will bind our variables and execute our insert.
Paste the following code over that comment:
```
if (!validator.isValid(request, responseObserver)) {
return;
}
```
This simply validates that the HTTP request is valid. Now add the following code below that:
```
final Date now = new Date();
final CommonTypes.Uuid userIdUuid = request.getUserId();
final UUID userIdUUID = UUID.fromString(userIdUuid.getValue());
final String firstName = request.getFirstName();
final String lastName = request.getLastName();
final String hashedPassword = HashUtils.hashPassword(request.getPassword().trim());
final String email = request.getEmail();
final String dupUserMessaage = String.format("Exception creating user because it already exists with email %s", email);
```
This pulls the values we are interested out of the HTTP request.
Now add the following:
```
final BoundStatement checkEmailQuery = createUser_checkEmailPrepared.bind()
.setString("email", email)
.setString("password", hashedPassword)
.setUUID("userid", userIdUUID);
```
This binds our `createUser_checkEmailPrepared` prepared statment to actual values, making a `BoundStatement` that we can actually `execute()`.
Continue adding:
```
ResultSet checkEmailResultSet = dseSession.execute(checkEmailQuery);
if (!checkEmailResultSet.wasApplied()) {
responseObserver.onError(Status.INVALID_ARGUMENT
.augmentDescription(dupUserMessaage).asRuntimeException());
responseObserver.onCompleted();
return;
}
```
Here we `execute()` our `BoundStatment` and further check that the insert `wasApplied()`. If not, we return an error.
Continue adding code:
```
final BoundStatement insertUser = createUser_insertUserPrepared.bind()
.setUUID("userid", userIdUUID)
.setString("firstname", firstName)
.setString("lastname", lastName)
.setString("email", email)
.setTimestamp("created_date", now);
ResultSet insertUserResultSet = dseSession.execute(insertUser);
if(!insertUserResultSet.wasApplied()) {
responseObserver.onError(Status.INVALID_ARGUMENT
.augmentDescription("User ID not unique").asRuntimeException());
responseObserver.onCompleted();
return;
}
```
This inserts the full user record into the `users` table. Again we check that the result applied.
Now finish serving the HTTP request by adding the following:
```
responseObserver.onNext(CreateUserResponse.newBuilder().build());
responseObserver.onCompleted();
```
--------------------CELL_MARKDOWN_7--------------------
The entire `createUser()` function should look like so:
```
@Override
public void createUser(CreateUserRequest request, StreamObserver<CreateUserResponse> responseObserver) {
if (!validator.isValid(request, responseObserver)) {
return;
}
final Date now = new Date();
final CommonTypes.Uuid userIdUuid = request.getUserId();
final UUID userIdUUID = UUID.fromString(userIdUuid.getValue());
final String firstName = request.getFirstName();
final String lastName = request.getLastName();
final String hashedPassword = HashUtils.hashPassword(request.getPassword().trim());
final String email = request.getEmail();
final String dupUserMessaage = String.format("Exception creating user because it already exists with email %s", email);
final BoundStatement checkEmailQuery = createUser_checkEmailPrepared.bind()
.setString("email", email)
.setString("password", hashedPassword)
.setUUID("userid", userIdUUID);
ResultSet checkEmailResultSet = dseSession.execute(checkEmailQuery);
if (!checkEmailResultSet.wasApplied()) {
responseObserver.onError(Status.INVALID_ARGUMENT
.augmentDescription(dupUserMessaage).asRuntimeException());
responseObserver.onCompleted();
return;
}
final BoundStatement insertUser = createUser_insertUserPrepared.bind()
.setUUID("userid", userIdUUID)
.setString("firstname", firstName)
.setString("lastname", lastName)
.setString("email", email)
.setTimestamp("created_date", now);
ResultSet insertUserResultSet = dseSession.execute(insertUser);
if(!insertUserResultSet.wasApplied()) {
responseObserver.onError(Status.INVALID_ARGUMENT
.augmentDescription("User ID not unique").asRuntimeException());
responseObserver.onCompleted();
return;
}
responseObserver.onNext(CreateUserResponse.newBuilder().build());
responseObserver.onCompleted();
}
```
--------------------CELL_MARKDOWN_8--------------------
Stop your previously running KillrVideo instance by clicking on the `X` under the `Machines` area towards the bottom of your Eclipse Che window.
<center>![Close Application](https://s3.amazonaws.com/datastaxtraining/developer-day/app-dev/close-appplication.PNG "Close Application" )</center>
Click OK to confirm this action.
Then re-run your application but using the `ALT-R` hot key.
Then go ahead and re-register then sign in with the user information you registered on the site with earlier. If it works properly, the site will redirect you to the home page.
YAY!