Add voting app example
[music.git] / examples / VotingApp / src / main / java / main / VotingApp.java
1 /*
2  * 
3 This licence applies to all files in this repository unless otherwise specifically
4 stated inside of the file. 
5
6  ---------------------------------------------------------------------------
7    Copyright (c) 2016 AT&T Intellectual Property
8
9    Licensed under the Apache License, Version 2.0 (the "License");
10    you may not use this file except in compliance with the License.
11    You may obtain a copy of the License at:
12
13        http://www.apache.org/licenses/LICENSE-2.0
14
15    Unless required by applicable law or agreed to in writing, software
16    distributed under the License is distributed on an "AS IS" BASIS,
17    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18    See the License for the specific language governing permissions and
19    limitations under the License.
20  ---------------------------------------------------------------------------
21
22  */
23 package main;
24 import java.io.BufferedReader;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Map;
31
32 import javax.ws.rs.core.MediaType;
33
34 import com.sun.jersey.api.client.Client;
35 import com.sun.jersey.api.client.ClientResponse;
36 import com.sun.jersey.api.client.WebResource;
37 import com.sun.jersey.api.client.WebResource.Builder;
38 import com.sun.jersey.api.client.config.ClientConfig;
39 import com.sun.jersey.api.client.config.DefaultClientConfig;
40 import com.sun.jersey.api.json.JSONConfiguration;
41
42 public class VotingApp {
43         String keyspaceName;
44         ArrayList<String> lockNames;
45         MusicConnector musicHandle;
46         private final String version="1.0.0";
47         
48         //UPDATE your onboarding information here
49         String namespace = "votingapp";
50         String userId = "abc123d";
51         String password = "password";
52         
53         public VotingApp(String[] musicIps){
54                 lockNames = new ArrayList<String>();    
55                 musicHandle = new MusicConnector(musicIps);
56                 bootStrap();
57         }
58         
59         /**
60          * Adds MUSIC's authentication headers into the webresource
61          * @param webResource
62          */
63         private Builder addMusicHeaders(WebResource webResource) {
64                 Builder builder = webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
65                 if (!namespace.equals("")) {
66                         builder.header("ns", namespace);
67                 }
68                 if (!userId.equals("")) {
69                         builder.header("userId", userId);
70                 }
71                 if (!password.equals("")) {
72                         builder.header("password", password);
73                 }
74                 
75                 return builder;
76         }
77         
78         public void createVotingKeyspace(){
79                 keyspaceName = "VotingAppForMusic";
80                 System.out.println("Voting app version "+ version+" .....");
81                 Map<String,Object> replicationInfo = new HashMap<String, Object>();
82                 replicationInfo.put("class", "SimpleStrategy");
83                 replicationInfo.put("replication_factor", 1);
84                 String durabilityOfWrites="false";
85                 Map<String,String> consistencyInfo= new HashMap<String, String>();
86                 consistencyInfo.put("type", "eventual");
87                 JsonKeySpace jsonKp = new JsonKeySpace();
88                 jsonKp.setConsistencyInfo(consistencyInfo);
89                 jsonKp.setDurabilityOfWrites(durabilityOfWrites);
90                 jsonKp.setReplicationInfo(replicationInfo);
91
92                 ClientConfig clientConfig = new DefaultClientConfig();
93
94                 clientConfig.getFeatures().put(
95                                 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
96
97                 Client client = Client.create(clientConfig);
98
99                 WebResource webResource = client
100                                 .resource(musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName);
101
102                 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
103                                 .type("application/json").post(ClientResponse.class, jsonKp);
104                 if (response.getStatus() < 200 || (response.getStatus() > 299 && response.getStatus()!=400)) { //supress keyspace already exists
105                         Map<String, String> map = response.getEntity(Map.class);
106                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus() + "- " + map);
107                 }
108
109         }
110
111         public void createVotingTable(){
112                 Map<String,String> fields = new HashMap<String,String>();
113                 fields.put("name", "text");
114                 fields.put("count", "varint");
115                 fields.put("PRIMARY KEY", "(name)");
116
117
118                 Map<String,String> consistencyInfo= new HashMap<String, String>();
119                 consistencyInfo.put("type", "eventual");
120
121                 JsonTable jtab = new JsonTable();
122                 jtab.setFields(fields);
123                 jtab.setConsistencyInfo(consistencyInfo);
124
125                 ClientConfig clientConfig = new DefaultClientConfig();
126
127                 clientConfig.getFeatures().put(
128                                 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
129
130                 Client client = Client.create(clientConfig);
131                 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount";
132                 System.out.println("create url:"+url);
133                 WebResource webResource = client
134                                 .resource(url);
135
136                 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
137                                 .type("application/json").post(ClientResponse.class, jtab);
138
139                 System.out.println(response.getEntity(Map.class));
140                 if (response.getStatus() < 200 || (response.getStatus() > 299 && response.getStatus()!=400)) 
141                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus());
142
143         }
144         private void checkMusicVersion(){
145                 Client client = Client.create();
146                 System.out.println(musicHandle.getMusicNodeURL()+"/version");
147                 
148
149 //              System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
150                 WebResource webResource = client
151                                 .resource(musicHandle.getMusicNodeURL()+"/version");
152                 
153
154                 ClientResponse response = addMusicHeaders(webResource)
155                                 .accept(MediaType.APPLICATION_JSON).header("Connection", "close").get(ClientResponse.class);
156                 
157                 if (response.getStatus() != 200) {
158                         throw new RuntimeException("Failed : HTTP error code : "
159                                         + response.getStatus());
160                 }
161
162                 String output = response.getEntity(Map.class).toString();
163
164                 System.out.println(output);
165
166         }
167
168         private  void createEntryForCandidate(String candidateName){
169                 Map<String,Object> values = new HashMap<String,Object>();
170                 values.put("name",candidateName );
171                 values.put("count",0);
172
173                 Map<String,String> consistencyInfo= new HashMap<String, String>();
174                 consistencyInfo.put("type", "eventual");
175
176                 JsonInsert jIns = new JsonInsert();
177                 jIns.setValues(values);
178                 jIns.setConsistencyInfo(consistencyInfo);
179                 ClientConfig clientConfig = new DefaultClientConfig();
180
181                 clientConfig.getFeatures().put(
182                                 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
183
184                 Client client = Client.create(clientConfig);
185
186                 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows";
187                 WebResource webResource = client
188                                 .resource(url);
189
190                 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
191                                 .type("application/json").post(ClientResponse.class, jIns);
192
193                 if (response.getStatus() < 200 || response.getStatus() > 299) 
194                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+url+" candidate name:"+ candidateName);
195
196
197         }
198
199         private  String createLock(String lockName){
200                 Client client = Client.create();
201                 String msg = musicHandle.getMusicNodeURL()+"/locks/create/"+lockName;
202                 WebResource webResource = client.resource(msg);
203                 System.out.println(msg);
204                 WebResource.Builder wb = addMusicHeaders(webResource).accept(MediaType.APPLICATION_JSON);
205
206                 ClientResponse response = wb.post(ClientResponse.class);
207
208                 if (response.getStatus() != 200) {
209                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+msg);
210                 }
211
212                 Map<String,Object> responseMap = response.getEntity(Map.class);
213
214                 String lockid = ((Map<String,String>) responseMap.get("lock")).get("lock");
215 //              System.out.println("Server response .... \n");
216 //              System.out.println(output);
217                 return lockid;
218         }
219
220         private  boolean acquireLock(String lockId){
221                 Client client = Client.create();
222                 String msg = musicHandle.getMusicNodeURL()+"/locks/acquire/"+lockId;
223                 System.out.println(msg);
224                 WebResource webResource = client.resource(msg);
225
226
227                 WebResource.Builder wb = addMusicHeaders(webResource).accept(MediaType.APPLICATION_JSON);
228
229                 ClientResponse response = wb.get(ClientResponse.class);
230
231                 Map<String, Object> responseMap = response.getEntity(Map.class);
232                 
233                 if (response.getStatus() != 200) {
234                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+ ":" + responseMap);
235                 }
236
237                 System.out.println(responseMap);
238                 Boolean status = responseMap.get("status").equals("SUCCESS");
239                 System.out.println("Server response .... " + status);
240                 return status;
241         }
242
243         private  void unlock(String lockId){
244                 Client client = Client.create();
245                 WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/locks/release/"+lockId);
246
247                 ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class);
248
249
250                 if (response.getStatus() < 200 || response.getStatus()>299) {
251                         throw new RuntimeException("Failed : HTTP error code : "
252                                         + response.getStatus());
253                 }
254         }
255
256         private  void updateVoteCountAtomically(String candidateName,int count){
257                 /*create lock for the candidate. The music API dictates that
258                  * the lock name must be of the form keyspacename.tableName.primaryKeyName
259                  * */
260                 System.out.println("trying to acquire lock!");
261
262                 String lockName = keyspaceName+".votecount."+candidateName;
263                 lockNames.add(lockName);
264                 String lockId = createLock(lockName);
265                 while(acquireLock(lockId) != true);
266                 
267                 System.out.println("acquired lock!");
268                 //update candidate entry if you have the lock
269                 Map<String,Object> values = new HashMap<String,Object>();
270                 values.put("count",count);
271
272                 Map<String,String> consistencyInfo= new HashMap<String, String>();
273                 consistencyInfo.put("type", "critical");
274                 consistencyInfo.put("lockId", lockId);
275
276                 JsonInsert jIns = new JsonInsert();
277                 jIns.setValues(values);
278                 jIns.setConsistencyInfo(consistencyInfo);
279                 ClientConfig clientConfig = new DefaultClientConfig();
280
281                 clientConfig.getFeatures().put(
282                                 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
283
284                 Client client = Client.create(clientConfig);
285                 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows?name="+candidateName;
286                 System.out.println(url);
287                 WebResource webResource = client
288                                 .resource(url);
289
290                 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
291                                 .type("application/json").put(ClientResponse.class, jIns);
292
293                 Map<String,String> map = response.getEntity(Map.class);
294                 
295                 if (response.getStatus() < 200 || response.getStatus() > 299) 
296                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+":"+map);
297
298                 //release lock now that the operation is done
299                 unlock(lockId);
300
301         }
302
303         private  void deleteCandidateEntryEventually(String candidateName){
304                 Map<String,String> consistencyInfo= new HashMap<String, String>();
305                 consistencyInfo.put("type", "eventual");
306
307                 JsonDelete jDel = new JsonDelete();
308                 jDel.setConsistencyInfo(consistencyInfo);
309                 ClientConfig clientConfig = new DefaultClientConfig();
310
311                 clientConfig.getFeatures().put(
312                                 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
313
314                 Client client = Client.create(clientConfig);
315                 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows?name="+candidateName;
316                 System.out.println(url);
317                 WebResource webResource = client
318                                 .resource(url);
319
320                 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
321                                 .type("application/json").delete(ClientResponse.class, jDel);
322
323                 if (response.getStatus() < 200 || response.getStatus() > 299) 
324                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+url);
325
326         }
327
328         public  Map<String,Object> readVoteCountForCandidate(String candidateName){
329                 ClientConfig clientConfig = new DefaultClientConfig();
330
331                 clientConfig.getFeatures().put(
332                                 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
333
334                 Client client = Client.create(clientConfig);
335                 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows?name="+candidateName;
336                 WebResource webResource = client
337                                 .resource(url);
338
339                 ClientResponse response = addMusicHeaders(webResource).accept("application/json").get(ClientResponse.class);
340
341                 if (response.getStatus() < 200 || response.getStatus() > 299) 
342                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus());
343                 
344                 Map<String,Object> output = response.getEntity(Map.class);
345                 return output;  
346         }
347
348         public  Map<String,Object> readAllVotes(){
349                 ClientConfig clientConfig = new DefaultClientConfig();
350
351                 clientConfig.getFeatures().put(
352                                 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
353
354                 Client client = Client.create(clientConfig);
355                 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows";
356                 WebResource webResource = client
357                                 .resource(url);
358
359                 ClientResponse response = addMusicHeaders(webResource).accept("application/json").get(ClientResponse.class);
360
361                 if (response.getStatus() < 200 || response.getStatus() > 299) 
362                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus());
363                 
364                 Map<String,Object> output = response.getEntity(Map.class);
365                 return output;  
366         }
367         
368         
369         /*
370          * Unable to use this because of the error: 
371          * Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: java.net.ProtocolException: 
372          * HTTP method DELETE doesn't support output. Seems to be a error in the rest java combination according to the interwebs
373          */
374         private void dropKeySpace(){
375                 Map<String,String> consistencyInfo= new HashMap<String, String>();
376                 consistencyInfo.put("type", "eventual");
377
378                 JsonKeySpace jsonKp = new JsonKeySpace();
379                 jsonKp.setConsistencyInfo(consistencyInfo);
380
381                 ClientConfig clientConfig = new DefaultClientConfig();
382
383                 clientConfig.getFeatures().put(
384                                 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
385
386                 Client client = Client.create(clientConfig);
387
388                 WebResource webResource = client
389                                 .resource(musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName);
390
391                 ClientResponse response = addMusicHeaders(webResource).type("application/json")
392                                 .delete(ClientResponse.class, jsonKp);
393
394                 if (response.getStatus() < 200 || response.getStatus() > 299) 
395                         throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus());
396         }
397         
398         private void deleteLock(String lockName){
399                 Client client = Client.create();
400                 WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/locks/delete/"+lockName);
401
402                 ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class);
403
404
405                 if (response.getStatus() <200 || response.getStatus()>299) {
406                         throw new RuntimeException("Failed : HTTP error code : "
407                                         + response.getStatus());
408                 }
409         }
410
411         private void resetMusic(){
412                 Client client = Client.create();
413                 WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/reset");
414
415                 ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class);
416
417
418                 if (response.getStatus() != 204) {
419                         throw new RuntimeException("Failed : HTTP error code : "
420                                         + response.getStatus());
421                 }
422                 
423         }
424         public void deleteAllLocks(){
425                 for (String lockName : lockNames) {
426                         deleteLock(lockName);
427                 }
428         }
429         
430         
431         public void bootStrap(){
432                 checkMusicVersion();
433                 createVotingKeyspace();
434
435
436                 createVotingTable();
437                 
438
439                 //the next few lines just create an entry in the voting table for all these candidates with vote count as 0
440                 createEntryForCandidate("Popeye");
441
442                 createEntryForCandidate("Judy");
443
444                 createEntryForCandidate("Flash");
445
446                 createEntryForCandidate("Mickey");
447
448         }
449         
450         public void overAllTests(){
451                 //update the count atomically
452                 updateVoteCountAtomically("Popeye",5);
453
454                 updateVoteCountAtomically("Judy",7);
455                 
456                 updateVoteCountAtomically("Mickey",8);
457
458                 updateVoteCountAtomically("Flash",2);
459
460                 
461                 //read votecount                
462                 System.out.println(readAllVotes());
463                 
464                 System.out.println(readVoteCountForCandidate("Popeye"));
465                 
466                 System.out.println(readVoteCountForCandidate("Flash"));
467
468                 deleteCandidateEntryEventually("Mickey");
469
470                 System.out.println(readAllVotes());
471
472 //              dropKeySpace();
473
474                 deleteAllLocks();
475         }
476         
477         public void flipTest(){
478                 checkMusicVersion();
479         }
480         
481         public static String executeBashScript(String pathToScript, String arg1, String arg2){
482                 try {
483                         ProcessBuilder pb = new ProcessBuilder(pathToScript,arg1, arg2);
484                         final Process process = pb.start();
485                         InputStream is = process.getInputStream();
486                         InputStreamReader isr = new InputStreamReader(is);
487                         BufferedReader br = new BufferedReader(isr);
488                         return br.readLine();
489                 } catch (IOException e) {
490                         e.printStackTrace();
491                 }
492                 return null;    
493         }
494         
495         public static void main(String[] args) {        
496                 long start = System.currentTimeMillis();
497
498                 if (args.length==0) {
499                         args = new String[]{"localhost"};
500                 }
501                 for(int i =0; i < 2;++i){
502                         VotingApp vHandle = new VotingApp(args);
503                         vHandle.overAllTests();
504
505                         System.out.println("=====================================");
506                         System.out.println("Test no."+i+" completed:");
507                 }
508                 long diff =     System.currentTimeMillis() - start;
509                 System.out.println(diff);
510         }
511                         
512
513 }