3 This licence applies to all files in this repository unless otherwise specifically
4 stated inside of the file.
6 ---------------------------------------------------------------------------
7 Copyright (c) 2016 AT&T Intellectual Property
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:
13 http://www.apache.org/licenses/LICENSE-2.0
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 ---------------------------------------------------------------------------
25 import java.io.BufferedReader;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.util.ArrayList;
30 import java.util.HashMap;
32 import java.util.Base64;
34 import javax.ws.rs.core.MediaType;
36 import com.sun.jersey.api.client.Client;
37 import com.sun.jersey.api.client.ClientResponse;
38 import com.sun.jersey.api.client.WebResource;
39 import com.sun.jersey.api.client.WebResource.Builder;
40 import com.sun.jersey.api.client.config.ClientConfig;
41 import com.sun.jersey.api.client.config.DefaultClientConfig;
42 import com.sun.jersey.api.json.JSONConfiguration;
44 public class VotingApp {
46 ArrayList<String> lockNames;
47 MusicConnector musicHandle;
48 private final String version="1.0.0";
50 //UPDATE your onboarding information here
51 String namespace = "votingapp";
52 String userId = "abc123d";
53 String password = "password";
55 public VotingApp(String[] musicIps){
56 lockNames = new ArrayList<String>();
57 musicHandle = new MusicConnector(musicIps);
62 * Adds MUSIC's authentication headers into the webresource
65 private Builder addMusicHeaders(WebResource webResource) {
66 Builder builder = webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON);
67 if (!namespace.equals("")) {
68 builder.header("ns", namespace);
70 if (!userId.equals("") && !password.equals("")) {
71 String authString = Base64.getEncoder().encodeToString((userId + ":" + password).getBytes());
72 builder.header("Authorization", "Basic " + authString);
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);
92 ClientConfig clientConfig = new DefaultClientConfig();
94 clientConfig.getFeatures().put(
95 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
97 Client client = Client.create(clientConfig);
99 WebResource webResource = client
100 .resource(musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName);
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);
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)");
118 Map<String,String> consistencyInfo= new HashMap<String, String>();
119 consistencyInfo.put("type", "eventual");
121 JsonTable jtab = new JsonTable();
122 jtab.setFields(fields);
123 jtab.setConsistencyInfo(consistencyInfo);
125 ClientConfig clientConfig = new DefaultClientConfig();
127 clientConfig.getFeatures().put(
128 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
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
136 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
137 .type("application/json").post(ClientResponse.class, jtab);
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());
144 private void checkMusicVersion(){
145 Client client = Client.create();
146 System.out.println(musicHandle.getMusicNodeURL()+"/version");
149 // System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
150 WebResource webResource = client
151 .resource(musicHandle.getMusicNodeURL()+"/version");
154 ClientResponse response = addMusicHeaders(webResource)
155 .accept(MediaType.APPLICATION_JSON).header("Connection", "close").get(ClientResponse.class);
157 if (response.getStatus() != 200) {
158 throw new RuntimeException("Failed : HTTP error code : "
159 + response.getStatus());
162 String output = response.getEntity(Map.class).toString();
164 System.out.println(output);
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);
173 Map<String,String> consistencyInfo= new HashMap<String, String>();
174 consistencyInfo.put("type", "eventual");
176 JsonInsert jIns = new JsonInsert();
177 jIns.setValues(values);
178 jIns.setConsistencyInfo(consistencyInfo);
179 ClientConfig clientConfig = new DefaultClientConfig();
181 clientConfig.getFeatures().put(
182 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
184 Client client = Client.create(clientConfig);
186 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows";
187 WebResource webResource = client
190 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
191 .type("application/json").post(ClientResponse.class, jIns);
193 if (response.getStatus() < 200 || response.getStatus() > 299)
194 throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+url+" candidate name:"+ candidateName);
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);
206 ClientResponse response = wb.post(ClientResponse.class);
208 if (response.getStatus() != 200) {
209 throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+msg);
212 Map<String,Object> responseMap = response.getEntity(Map.class);
214 String lockid = ((Map<String,String>) responseMap.get("lock")).get("lock");
215 // System.out.println("Server response .... \n");
216 // System.out.println(output);
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);
227 WebResource.Builder wb = addMusicHeaders(webResource).accept(MediaType.APPLICATION_JSON);
229 ClientResponse response = wb.get(ClientResponse.class);
231 Map<String, Object> responseMap = response.getEntity(Map.class);
233 if (response.getStatus() != 200) {
234 throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+ ":" + responseMap);
237 System.out.println(responseMap);
238 Boolean status = responseMap.get("status").equals("SUCCESS");
239 System.out.println("Server response .... " + status);
243 private void unlock(String lockId){
244 Client client = Client.create();
245 WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/locks/release/"+lockId);
247 ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class);
250 if (response.getStatus() < 200 || response.getStatus()>299) {
251 throw new RuntimeException("Failed : HTTP error code : "
252 + response.getStatus());
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
260 System.out.println("trying to acquire lock!");
262 String lockName = keyspaceName+".votecount."+candidateName;
263 lockNames.add(lockName);
264 String lockId = createLock(lockName);
265 while(acquireLock(lockId) != true);
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);
272 Map<String,String> consistencyInfo= new HashMap<String, String>();
273 consistencyInfo.put("type", "critical");
274 consistencyInfo.put("lockId", lockId);
276 JsonInsert jIns = new JsonInsert();
277 jIns.setValues(values);
278 jIns.setConsistencyInfo(consistencyInfo);
279 ClientConfig clientConfig = new DefaultClientConfig();
281 clientConfig.getFeatures().put(
282 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
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
290 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
291 .type("application/json").put(ClientResponse.class, jIns);
293 Map<String,String> map = response.getEntity(Map.class);
295 if (response.getStatus() < 200 || response.getStatus() > 299)
296 throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+":"+map);
298 //release lock now that the operation is done
303 private void deleteCandidateEntryEventually(String candidateName){
304 Map<String,String> consistencyInfo= new HashMap<String, String>();
305 consistencyInfo.put("type", "eventual");
307 JsonDelete jDel = new JsonDelete();
308 jDel.setConsistencyInfo(consistencyInfo);
309 ClientConfig clientConfig = new DefaultClientConfig();
311 clientConfig.getFeatures().put(
312 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
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
320 ClientResponse response = addMusicHeaders(webResource).accept("application/json")
321 .type("application/json").delete(ClientResponse.class, jDel);
323 if (response.getStatus() < 200 || response.getStatus() > 299)
324 throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+url);
328 public Map<String,Object> readVoteCountForCandidate(String candidateName){
329 ClientConfig clientConfig = new DefaultClientConfig();
331 clientConfig.getFeatures().put(
332 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
334 Client client = Client.create(clientConfig);
335 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows?name="+candidateName;
336 WebResource webResource = client
339 ClientResponse response = addMusicHeaders(webResource).accept("application/json").get(ClientResponse.class);
341 if (response.getStatus() < 200 || response.getStatus() > 299)
342 throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus());
344 Map<String,Object> output = response.getEntity(Map.class);
348 public Map<String,Object> readAllVotes(){
349 ClientConfig clientConfig = new DefaultClientConfig();
351 clientConfig.getFeatures().put(
352 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
354 Client client = Client.create(clientConfig);
355 String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows";
356 WebResource webResource = client
359 ClientResponse response = addMusicHeaders(webResource).accept("application/json").get(ClientResponse.class);
361 if (response.getStatus() < 200 || response.getStatus() > 299)
362 throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus());
364 Map<String,Object> output = response.getEntity(Map.class);
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
374 private void dropKeySpace(){
375 Map<String,String> consistencyInfo= new HashMap<String, String>();
376 consistencyInfo.put("type", "eventual");
378 JsonKeySpace jsonKp = new JsonKeySpace();
379 jsonKp.setConsistencyInfo(consistencyInfo);
381 ClientConfig clientConfig = new DefaultClientConfig();
383 clientConfig.getFeatures().put(
384 JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
386 Client client = Client.create(clientConfig);
388 WebResource webResource = client
389 .resource(musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName);
391 ClientResponse response = addMusicHeaders(webResource).type("application/json")
392 .delete(ClientResponse.class, jsonKp);
394 if (response.getStatus() < 200 || response.getStatus() > 299)
395 throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus());
398 private void deleteLock(String lockName){
399 Client client = Client.create();
400 WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/locks/delete/"+lockName);
402 ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class);
405 if (response.getStatus() <200 || response.getStatus()>299) {
406 throw new RuntimeException("Failed : HTTP error code : "
407 + response.getStatus());
411 private void resetMusic(){
412 Client client = Client.create();
413 WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/reset");
415 ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class);
418 if (response.getStatus() != 204) {
419 throw new RuntimeException("Failed : HTTP error code : "
420 + response.getStatus());
424 public void deleteAllLocks(){
425 for (String lockName : lockNames) {
426 deleteLock(lockName);
431 public void bootStrap(){
433 createVotingKeyspace();
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");
442 createEntryForCandidate("Judy");
444 createEntryForCandidate("Flash");
446 createEntryForCandidate("Mickey");
450 public void overAllTests(){
451 //update the count atomically
452 updateVoteCountAtomically("Popeye",5);
454 updateVoteCountAtomically("Judy",7);
456 updateVoteCountAtomically("Mickey",8);
458 updateVoteCountAtomically("Flash",2);
462 System.out.println(readAllVotes());
464 System.out.println(readVoteCountForCandidate("Popeye"));
466 System.out.println(readVoteCountForCandidate("Flash"));
468 deleteCandidateEntryEventually("Mickey");
470 System.out.println(readAllVotes());
477 public void flipTest(){
481 public static String executeBashScript(String pathToScript, String arg1, String arg2){
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) {
495 public static void main(String[] args) {
496 long start = System.currentTimeMillis();
498 if (args.length==0) {
499 args = new String[]{"localhost"};
501 for(int i =0; i < 2;++i){
502 VotingApp vHandle = new VotingApp(args);
503 vHandle.overAllTests();
505 System.out.println("=====================================");
506 System.out.println("Test no."+i+" completed:");
508 long diff = System.currentTimeMillis() - start;
509 System.out.println(diff);