From 46350c084766789ea59e83f1917c57c81d653048 Mon Sep 17 00:00:00 2001 From: "Tschaen, Brendan" Date: Tue, 16 Oct 2018 20:22:35 -0400 Subject: Include Cassandra locking Change-Id: I085acf8336d5f27782ee12768846a5befd3ee60d Issue-ID: MUSIC-148 Signed-off-by: Tschaen, Brendan --- example/VotingApp/README.md | 31 ++ example/VotingApp/pom.xml | 92 ++++ .../VotingApp/src/main/java/main/JsonDelete.java | 61 +++ .../VotingApp/src/main/java/main/JsonInsert.java | 67 +++ .../VotingApp/src/main/java/main/JsonKeySpace.java | 58 +++ .../VotingApp/src/main/java/main/JsonTable.java | 55 +++ .../src/main/java/main/MusicConnector.java | 76 +++ example/VotingApp/src/main/java/main/Util.java | 6 + .../VotingApp/src/main/java/main/VotingAppJar.java | 115 +++++ .../src/main/java/main/VotingAppREST.java | 513 +++++++++++++++++++++ example/VotingAppJar/VotingAppJar/pom.xml | 30 ++ .../org/onap/music/VotingAppJar/VotingAppJar.java | 115 +++++ .../java/org/onap/music/VotingAppJar/AppTest.java | 38 ++ 13 files changed, 1257 insertions(+) create mode 100644 example/VotingApp/README.md create mode 100644 example/VotingApp/pom.xml create mode 100644 example/VotingApp/src/main/java/main/JsonDelete.java create mode 100644 example/VotingApp/src/main/java/main/JsonInsert.java create mode 100644 example/VotingApp/src/main/java/main/JsonKeySpace.java create mode 100644 example/VotingApp/src/main/java/main/JsonTable.java create mode 100644 example/VotingApp/src/main/java/main/MusicConnector.java create mode 100644 example/VotingApp/src/main/java/main/Util.java create mode 100644 example/VotingApp/src/main/java/main/VotingAppJar.java create mode 100644 example/VotingApp/src/main/java/main/VotingAppREST.java create mode 100644 example/VotingAppJar/VotingAppJar/pom.xml create mode 100644 example/VotingAppJar/VotingAppJar/src/main/java/org/onap/music/VotingAppJar/VotingAppJar.java create mode 100644 example/VotingAppJar/VotingAppJar/src/test/java/org/onap/music/VotingAppJar/AppTest.java (limited to 'example') diff --git a/example/VotingApp/README.md b/example/VotingApp/README.md new file mode 100644 index 00000000..bcd37b9b --- /dev/null +++ b/example/VotingApp/README.md @@ -0,0 +1,31 @@ + +The voting app for MUSIC illustrates the features of MUSIC as a +multi-site state management +service. It is a program that +maintains state in MUSIC in the form of a vote-count table that has two columns, the candidateName +and his voteCount. To the external client that is using the voting app to update votes, the +votingApp provides a simple function to update the +votecount of the candidate in an exclusive manner. This is possible because of the locking service +in MUSIC. Since each candidate is a key in MUSIC, the votingapp simply acquires the geo-distributed +lock and only then upates the count. This guarantees correctness even when clients access different +end-points across data centers. Further since state is replicated correctly across data-centers, +even when one of the data centers fail, functioning can continue simply by using the MUSIC end point +in the other data center. + +The main function in the VotingApp.java is emulating clients from different data centers by randomly +chosing MUSIC end points. By updating vote counts +randomly using different MUSIC end points and still receiving the correct total count when doing a +read, the main function indicates the multi-site capability of MUSIC. + + +To run the application, make sure you have onboarded the application using music's admin api. +A curl call using the default values would be: +curl -X POST \ + http://localhost:8080/MUSIC/rest/v2/admin/onboardAppWithMusic \ + -H 'Content-Type: application/json' \ + -d '{ +"appname" : "votingapp", +"userId" : "abc123d", +"password" : "password", +"isAAF" : false +}' diff --git a/example/VotingApp/pom.xml b/example/VotingApp/pom.xml new file mode 100644 index 00000000..87cac6c0 --- /dev/null +++ b/example/VotingApp/pom.xml @@ -0,0 +1,92 @@ + + + 4.0.0 + com.att.reserarch.VoteAppForMUSIC + VoteAppForMUSIC + 0.0.1-SNAPSHOT + + + + + maven2-repository.java.net + Java.net Repository for Maven + http://download.java.net/maven/2/ + default + + + + + + + com.sun.jersey + jersey-server + 1.9 + + + com.sun.jersey + jersey-json + 1.18.1 + + + com.owlike + genson + 0.99 + + + com.sun.jersey + jersey-client + 1.9 + + + + com.sun.jersey + jersey-json + 1.9 + + + + com.sun.jersey + jersey-bundle + 1.18 + + + + com.googlecode.json-simple + json-simple + 1.1 + + + com.datastax.cassandra + cassandra-driver-core + 3.0.0 + + + org.apache.zookeeper + zookeeper + 3.4.6 + + + + + \ No newline at end of file diff --git a/example/VotingApp/src/main/java/main/JsonDelete.java b/example/VotingApp/src/main/java/main/JsonDelete.java new file mode 100644 index 00000000..9b75f875 --- /dev/null +++ b/example/VotingApp/src/main/java/main/JsonDelete.java @@ -0,0 +1,61 @@ +/* + * +This licence applies to all files in this repository unless otherwise specifically +stated inside of the file. + + --------------------------------------------------------------------------- + Copyright (c) 2016 AT&T Intellectual Property + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --------------------------------------------------------------------------- + + */ +package main; + +import java.util.ArrayList; +import java.util.Map; + +public class JsonDelete { + + private ArrayList columns = null; + private Map consistencyInfo; + + public Map getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + public ArrayList getColumns() { + return columns; + } + public void setColumns(ArrayList columns) { + this.columns = columns; + } + String ttl, timestamp; + + public String getTtl() { + return ttl; + } + public void setTtl(String ttl) { + this.ttl = ttl; + } + public String getTimestamp() { + return timestamp; + } + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } +} diff --git a/example/VotingApp/src/main/java/main/JsonInsert.java b/example/VotingApp/src/main/java/main/JsonInsert.java new file mode 100644 index 00000000..a2099c16 --- /dev/null +++ b/example/VotingApp/src/main/java/main/JsonInsert.java @@ -0,0 +1,67 @@ +/* + * +This licence applies to all files in this repository unless otherwise specifically +stated inside of the file. + + --------------------------------------------------------------------------- + Copyright (c) 2016 AT&T Intellectual Property + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --------------------------------------------------------------------------- + + */ +package main; + +import java.util.Map; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +public class JsonInsert { + + private Map values; + String ttl, timestamp; + private Map row_specification; + private Map consistencyInfo; + + public Map getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + public String getTtl() { + return ttl; + } + public void setTtl(String ttl) { + this.ttl = ttl; + } + public String getTimestamp() { + return timestamp; + } + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + public Map getValues() { + return values; + } + public void setValues(Map values) { + this.values = values; + } + public Map getRow_specification() { + return row_specification; + } + public void setRow_specification(Map row_specification) { + this.row_specification = row_specification; + } +} diff --git a/example/VotingApp/src/main/java/main/JsonKeySpace.java b/example/VotingApp/src/main/java/main/JsonKeySpace.java new file mode 100644 index 00000000..ff7b6c67 --- /dev/null +++ b/example/VotingApp/src/main/java/main/JsonKeySpace.java @@ -0,0 +1,58 @@ +/* + * +This licence applies to all files in this repository unless otherwise specifically +stated inside of the file. + + --------------------------------------------------------------------------- + Copyright (c) 2016 AT&T Intellectual Property + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --------------------------------------------------------------------------- + + */ +package main; + +import java.util.Map; + + +public class JsonKeySpace { + private Map replicationInfo; + private String durabilityOfWrites; + private Map consistencyInfo; + + public Map getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + public Map getReplicationInfo() { + return replicationInfo; + } + + public void setReplicationInfo(Map replicationInfo) { + this.replicationInfo = replicationInfo; + } + + public String getDurabilityOfWrites() { + return durabilityOfWrites; + } + public void setDurabilityOfWrites(String durabilityOfWrites) { + this.durabilityOfWrites = durabilityOfWrites; + } + + + +} diff --git a/example/VotingApp/src/main/java/main/JsonTable.java b/example/VotingApp/src/main/java/main/JsonTable.java new file mode 100644 index 00000000..66171af2 --- /dev/null +++ b/example/VotingApp/src/main/java/main/JsonTable.java @@ -0,0 +1,55 @@ +/* + * +This licence applies to all files in this repository unless otherwise specifically +stated inside of the file. + + --------------------------------------------------------------------------- + Copyright (c) 2016 AT&T Intellectual Property + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --------------------------------------------------------------------------- + + */ +package main; +import java.util.Map; + +public class JsonTable { + private Map fields; + private Map properties; + private Map consistencyInfo; + + + public Map getConsistencyInfo() { + return consistencyInfo; + } + + public void setConsistencyInfo(Map consistencyInfo) { + this.consistencyInfo = consistencyInfo; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public Map getFields() { + return fields; + } + + public void setFields(Map fields) { + this.fields = fields; + } +} diff --git a/example/VotingApp/src/main/java/main/MusicConnector.java b/example/VotingApp/src/main/java/main/MusicConnector.java new file mode 100644 index 00000000..d6ed20ba --- /dev/null +++ b/example/VotingApp/src/main/java/main/MusicConnector.java @@ -0,0 +1,76 @@ +/* + * +This licence applies to all files in this repository unless otherwise specifically +stated inside of the file. + + --------------------------------------------------------------------------- + Copyright (c) 2016 AT&T Intellectual Property + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --------------------------------------------------------------------------- + + */ +package main; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Random; + +public class MusicConnector { + + //change this to point to relevant cluster + public String[] musicNodes; + + public MusicConnector(String[] musicNodes){ + this.musicNodes = musicNodes; + } + + private String getMusicNodeIp(){ + Random r = new Random(); + int index = r.nextInt(musicNodes.length); + return musicNodes[index]; + } + + public String getMusicNodeURL(){ + String musicurl = "http://"+getMusicNodeIp()+":8080/MUSIC/rest/v2"; + return musicurl; + } + + public boolean isHostUp(String serverAddress) { + Boolean isUp = false; + try { + InetAddress inet = InetAddress.getByName(serverAddress); + isUp = inet.isReachable(1000); + } catch (UnknownHostException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return isUp; + } + + /* + private static String getMusicNodeIp(){ + + //return "54.224.168.13"; + return bigSiteMusicNode; + String serverAddress; + serverAddress = agaveMusicNode; + while(isHostUp(serverAddress) != true) + serverAddress = toggle(serverAddress); + return serverAddress; + }*/ +} diff --git a/example/VotingApp/src/main/java/main/Util.java b/example/VotingApp/src/main/java/main/Util.java new file mode 100644 index 00000000..aefa9a36 --- /dev/null +++ b/example/VotingApp/src/main/java/main/Util.java @@ -0,0 +1,6 @@ +package main; + +public class Util { + public static final String version="1.0.0"; + +} diff --git a/example/VotingApp/src/main/java/main/VotingAppJar.java b/example/VotingApp/src/main/java/main/VotingAppJar.java new file mode 100644 index 00000000..f73e9059 --- /dev/null +++ b/example/VotingApp/src/main/java/main/VotingAppJar.java @@ -0,0 +1,115 @@ +package main; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.exceptions.MusicLockingException; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; + +/** + * + */ +public class VotingAppJar +{ + String keyspaceName; + String tableName; + + public VotingAppJar() throws MusicServiceException { + keyspaceName = "VotingAppForMusic"; + tableName = "votevount"; + + createVotingKeyspace(); + System.out.println("Created keyspaces"); + createVotingTable(); + System.out.println("Created tables"); + + createEntryForCandidate("Popeye"); + createEntryForCandidate("Judy"); + createEntryForCandidate("Flash"); + createEntryForCandidate("Mickey"); + System.out.println("Created candidates"); + } + + private void createVotingKeyspace() throws MusicServiceException { + + Map replicationInfo = new HashMap(); + replicationInfo.put("'class'", "'SimpleStrategy'"); + replicationInfo.put("'replication_factor'", 1); + + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "CREATE KEYSPACE " + keyspaceName + " WITH REPLICATION = " + replicationInfo.toString().replaceAll("=", ":")); + + try { + MusicCore.nonKeyRelatedPut(queryObject, "eventual"); + } catch (MusicServiceException e) { + if (e.getMessage().equals("Keyspace votingappformusic already exists")) { + // ignore + } else { + throw(e); + } + } + } + + private void createVotingTable() throws MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "CREATE TABLE " + keyspaceName + "." + tableName + " (name text PRIMARY KEY, count varint);"); + + try { + MusicCore.createTable(keyspaceName, tableName, queryObject, "eventual"); + } catch (MusicServiceException e) { + if (e.getMessage().equals("Table votingappformusic.votevount already exists")) { + //ignore + } else { + throw(e); + } + } + } + + private void createEntryForCandidate(String candidateName) throws MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "INSERT INTO " + keyspaceName + "." + tableName + " (name, count) " + + "VALUES ('"+candidateName+"', 0);"); + + MusicCore.nonKeyRelatedPut(queryObject, "eventual"); + } + + public void vote() throws MusicLockingException, MusicQueryException, MusicServiceException { + updateVoteCount("Popeye",5); + updateVoteCount("Judy",7); + updateVoteCount("Mickey",8); + updateVoteCount("Flash",2); + } + + private void updateVoteCount(String candidateName, int numVotes) throws MusicLockingException, MusicQueryException, MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "INSERT INTO " + keyspaceName + "." + tableName + " (name, count) " + + "VALUES ('"+candidateName+"', "+numVotes+");"); + MusicCore.atomicPut(keyspaceName, tableName, candidateName, queryObject, null); + } + + private void readAllVotes() throws MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString("SELECT * FROM " + keyspaceName + "." + tableName); + ResultSet rs = MusicCore.get(queryObject); + for(Row candidate : rs.all()) { + System.out.println(candidate.getString("name") + " - " + candidate.getVarint("count")); + } + } + + public static void main( String[] args ) throws Exception { + VotingAppJar vHandle = new VotingAppJar(); + vHandle.vote(); + vHandle.readAllVotes(); + } + +} \ No newline at end of file diff --git a/example/VotingApp/src/main/java/main/VotingAppREST.java b/example/VotingApp/src/main/java/main/VotingAppREST.java new file mode 100644 index 00000000..a7b08368 --- /dev/null +++ b/example/VotingApp/src/main/java/main/VotingAppREST.java @@ -0,0 +1,513 @@ +/* + * +This licence applies to all files in this repository unless otherwise specifically +stated inside of the file. + + --------------------------------------------------------------------------- + Copyright (c) 2016 AT&T Intellectual Property + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --------------------------------------------------------------------------- + + */ +package main; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import javax.ws.rs.core.MediaType; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.WebResource.Builder; +import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.api.json.JSONConfiguration; + +public class VotingAppREST { + String keyspaceName; + ArrayList lockNames; + MusicConnector musicHandle; + private final String version="1.0.0"; + + //UPDATE your onboarding information here + String namespace = "votingapp"; + String userId = "abc123d"; + String password = "password"; + + public VotingAppREST(String[] musicIps){ + lockNames = new ArrayList(); + musicHandle = new MusicConnector(musicIps); + bootStrap(); + } + + /** + * Adds MUSIC's authentication headers into the webresource + * @param webResource + */ + private Builder addMusicHeaders(WebResource webResource) { + Builder builder = webResource.accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON); + if (!namespace.equals("")) { + builder.header("ns", namespace); + } + if (!userId.equals("")) { + builder.header("userId", userId); + } + if (!password.equals("")) { + builder.header("password", password); + } + + return builder; + } + + public void createVotingKeyspace(){ + keyspaceName = "VotingAppForMusic"; + System.out.println("Voting app version "+ version+" ....."); + Map replicationInfo = new HashMap(); + replicationInfo.put("class", "SimpleStrategy"); + replicationInfo.put("replication_factor", 1); + String durabilityOfWrites="false"; + Map consistencyInfo= new HashMap(); + consistencyInfo.put("type", "eventual"); + JsonKeySpace jsonKp = new JsonKeySpace(); + jsonKp.setConsistencyInfo(consistencyInfo); + jsonKp.setDurabilityOfWrites(durabilityOfWrites); + jsonKp.setReplicationInfo(replicationInfo); + + ClientConfig clientConfig = new DefaultClientConfig(); + + clientConfig.getFeatures().put( + JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + + Client client = Client.create(clientConfig); + + WebResource webResource = client + .resource(musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName); + + ClientResponse response = addMusicHeaders(webResource).accept("application/json") + .type("application/json").post(ClientResponse.class, jsonKp); + if (response.getStatus() < 200 || (response.getStatus() > 299 && response.getStatus()!=400)) { //supress keyspace already exists + Map map = response.getEntity(Map.class); + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus() + "- " + map); + } + + } + + public void createVotingTable(){ + Map fields = new HashMap(); + fields.put("name", "text"); + fields.put("count", "varint"); + fields.put("PRIMARY KEY", "(name)"); + + + Map consistencyInfo= new HashMap(); + consistencyInfo.put("type", "eventual"); + + JsonTable jtab = new JsonTable(); + jtab.setFields(fields); + jtab.setConsistencyInfo(consistencyInfo); + + ClientConfig clientConfig = new DefaultClientConfig(); + + clientConfig.getFeatures().put( + JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + + Client client = Client.create(clientConfig); + String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount"; + System.out.println("create url:"+url); + WebResource webResource = client + .resource(url); + + ClientResponse response = addMusicHeaders(webResource).accept("application/json") + .type("application/json").post(ClientResponse.class, jtab); + + System.out.println(response.getEntity(Map.class)); + if (response.getStatus() < 200 || (response.getStatus() > 299 && response.getStatus()!=400)) + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()); + + } + private void checkMusicVersion(){ + Client client = Client.create(); + System.out.println(musicHandle.getMusicNodeURL()+"/version"); + + +// System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); + WebResource webResource = client + .resource(musicHandle.getMusicNodeURL()+"/version"); + + + ClientResponse response = addMusicHeaders(webResource) + .accept(MediaType.APPLICATION_JSON).header("Connection", "close").get(ClientResponse.class); + + if (response.getStatus() != 200) { + throw new RuntimeException("Failed : HTTP error code : " + + response.getStatus()); + } + + String output = response.getEntity(Map.class).toString(); + + System.out.println(output); + + } + + private void createEntryForCandidate(String candidateName){ + Map values = new HashMap(); + values.put("name",candidateName ); + values.put("count",0); + + Map consistencyInfo= new HashMap(); + consistencyInfo.put("type", "eventual"); + + JsonInsert jIns = new JsonInsert(); + jIns.setValues(values); + jIns.setConsistencyInfo(consistencyInfo); + ClientConfig clientConfig = new DefaultClientConfig(); + + clientConfig.getFeatures().put( + JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + + Client client = Client.create(clientConfig); + + String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows"; + WebResource webResource = client + .resource(url); + + ClientResponse response = addMusicHeaders(webResource).accept("application/json") + .type("application/json").post(ClientResponse.class, jIns); + + if (response.getStatus() < 200 || response.getStatus() > 299) + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+url+" candidate name:"+ candidateName); + + + } + + private String createLock(String lockName){ + Client client = Client.create(); + String msg = musicHandle.getMusicNodeURL()+"/locks/create/"+lockName; + WebResource webResource = client.resource(msg); + System.out.println(msg); + WebResource.Builder wb = addMusicHeaders(webResource).accept(MediaType.APPLICATION_JSON); + + ClientResponse response = wb.post(ClientResponse.class); + + if (response.getStatus() != 200) { + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+msg); + } + + Map responseMap = response.getEntity(Map.class); + + String lockid = ((Map) responseMap.get("lock")).get("lock"); +// System.out.println("Server response .... \n"); +// System.out.println(output); + return lockid; + } + + private boolean acquireLock(String lockId){ + Client client = Client.create(); + String msg = musicHandle.getMusicNodeURL()+"/locks/acquire/"+lockId; + System.out.println(msg); + WebResource webResource = client.resource(msg); + + + WebResource.Builder wb = addMusicHeaders(webResource).accept(MediaType.APPLICATION_JSON); + + ClientResponse response = wb.get(ClientResponse.class); + + Map responseMap = response.getEntity(Map.class); + + if (response.getStatus() != 200) { + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+ ":" + responseMap); + } + + System.out.println(responseMap); + Boolean status = responseMap.get("status").equals("SUCCESS"); + System.out.println("Server response .... " + status); + return status; + } + + private void unlock(String lockId){ + Client client = Client.create(); + WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/locks/release/"+lockId); + + ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class); + + + if (response.getStatus() < 200 || response.getStatus()>299) { + throw new RuntimeException("Failed : HTTP error code : " + + response.getStatus()); + } + } + + private void updateVoteCountAtomically(String candidateName,int count){ + /*create lock for the candidate. The music API dictates that + * the lock name must be of the form keyspacename.tableName.primaryKeyName + * */ + System.out.println("trying to acquire lock!"); + + String lockName = keyspaceName+".votecount."+candidateName; + lockNames.add(lockName); + String lockId = createLock(lockName); + while(acquireLock(lockId) != true); + + System.out.println("acquired lock!"); + //update candidate entry if you have the lock + Map values = new HashMap(); + values.put("count",count); + + Map consistencyInfo= new HashMap(); + consistencyInfo.put("type", "critical"); + consistencyInfo.put("lockId", lockId); + + JsonInsert jIns = new JsonInsert(); + jIns.setValues(values); + jIns.setConsistencyInfo(consistencyInfo); + ClientConfig clientConfig = new DefaultClientConfig(); + + clientConfig.getFeatures().put( + JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + + Client client = Client.create(clientConfig); + String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows?name="+candidateName; + System.out.println(url); + WebResource webResource = client + .resource(url); + + ClientResponse response = addMusicHeaders(webResource).accept("application/json") + .type("application/json").put(ClientResponse.class, jIns); + + Map map = response.getEntity(Map.class); + + if (response.getStatus() < 200 || response.getStatus() > 299) + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+":"+map); + + //release lock now that the operation is done + unlock(lockId); + + } + + private void deleteCandidateEntryEventually(String candidateName){ + Map consistencyInfo= new HashMap(); + consistencyInfo.put("type", "eventual"); + + JsonDelete jDel = new JsonDelete(); + jDel.setConsistencyInfo(consistencyInfo); + ClientConfig clientConfig = new DefaultClientConfig(); + + clientConfig.getFeatures().put( + JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + + Client client = Client.create(clientConfig); + String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows?name="+candidateName; + System.out.println(url); + WebResource webResource = client + .resource(url); + + ClientResponse response = addMusicHeaders(webResource).accept("application/json") + .type("application/json").delete(ClientResponse.class, jDel); + + if (response.getStatus() < 200 || response.getStatus() > 299) + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()+"url:"+url); + + } + + public Map readVoteCountForCandidate(String candidateName){ + ClientConfig clientConfig = new DefaultClientConfig(); + + clientConfig.getFeatures().put( + JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + + Client client = Client.create(clientConfig); + String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows?name="+candidateName; + WebResource webResource = client + .resource(url); + + ClientResponse response = addMusicHeaders(webResource).accept("application/json").get(ClientResponse.class); + + if (response.getStatus() < 200 || response.getStatus() > 299) + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()); + + Map output = response.getEntity(Map.class); + return output; + } + + public Map readAllVotes(){ + ClientConfig clientConfig = new DefaultClientConfig(); + + clientConfig.getFeatures().put( + JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + + Client client = Client.create(clientConfig); + String url = musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName+"/tables/votecount/rows"; + WebResource webResource = client + .resource(url); + + ClientResponse response = addMusicHeaders(webResource).accept("application/json").get(ClientResponse.class); + + if (response.getStatus() < 200 || response.getStatus() > 299) + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()); + + Map output = response.getEntity(Map.class); + return output; + } + + + /* + * Unable to use this because of the error: + * Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: java.net.ProtocolException: + * HTTP method DELETE doesn't support output. Seems to be a error in the rest java combination according to the interwebs + */ + private void dropKeySpace(){ + Map consistencyInfo= new HashMap(); + consistencyInfo.put("type", "eventual"); + + JsonKeySpace jsonKp = new JsonKeySpace(); + jsonKp.setConsistencyInfo(consistencyInfo); + + ClientConfig clientConfig = new DefaultClientConfig(); + + clientConfig.getFeatures().put( + JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + + Client client = Client.create(clientConfig); + + WebResource webResource = client + .resource(musicHandle.getMusicNodeURL()+"/keyspaces/"+keyspaceName); + + ClientResponse response = addMusicHeaders(webResource).type("application/json") + .delete(ClientResponse.class, jsonKp); + + if (response.getStatus() < 200 || response.getStatus() > 299) + throw new RuntimeException("Failed : HTTP error code : "+ response.getStatus()); + } + + private void deleteLock(String lockName){ + Client client = Client.create(); + WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/locks/delete/"+lockName); + + ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class); + + + if (response.getStatus() <200 || response.getStatus()>299) { + throw new RuntimeException("Failed : HTTP error code : " + + response.getStatus()); + } + } + + private void resetMusic(){ + Client client = Client.create(); + WebResource webResource = client.resource(musicHandle.getMusicNodeURL()+"/reset"); + + ClientResponse response = addMusicHeaders(webResource).delete(ClientResponse.class); + + + if (response.getStatus() != 204) { + throw new RuntimeException("Failed : HTTP error code : " + + response.getStatus()); + } + + } + public void deleteAllLocks(){ + for (String lockName : lockNames) { + deleteLock(lockName); + } + } + + + public void bootStrap(){ + checkMusicVersion(); + createVotingKeyspace(); + + + createVotingTable(); + + + //the next few lines just create an entry in the voting table for all these candidates with vote count as 0 + createEntryForCandidate("Popeye"); + + createEntryForCandidate("Judy"); + + createEntryForCandidate("Flash"); + + createEntryForCandidate("Mickey"); + + } + + public void overAllTests(){ + //update the count atomically + updateVoteCountAtomically("Popeye",5); + + updateVoteCountAtomically("Judy",7); + + updateVoteCountAtomically("Mickey",8); + + updateVoteCountAtomically("Flash",2); + + + //read votecount + System.out.println(readAllVotes()); + + System.out.println(readVoteCountForCandidate("Popeye")); + + System.out.println(readVoteCountForCandidate("Flash")); + + deleteCandidateEntryEventually("Mickey"); + + System.out.println(readAllVotes()); + +// dropKeySpace(); + + deleteAllLocks(); + } + + public void flipTest(){ + checkMusicVersion(); + } + + public static String executeBashScript(String pathToScript, String arg1, String arg2){ + try { + ProcessBuilder pb = new ProcessBuilder(pathToScript,arg1, arg2); + final Process process = pb.start(); + InputStream is = process.getInputStream(); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + return br.readLine(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static void main(String[] args) { + long start = System.currentTimeMillis(); + + if (args.length==0) { + args = new String[]{"localhost"}; + } + for(int i =0; i < 2;++i){ + VotingAppREST vHandle = new VotingAppREST(args); + vHandle.overAllTests(); + + System.out.println("====================================="); + System.out.println("Test no."+i+" completed:"); + } + long diff = System.currentTimeMillis() - start; + System.out.println(diff); + } + + +} \ No newline at end of file diff --git a/example/VotingAppJar/VotingAppJar/pom.xml b/example/VotingAppJar/VotingAppJar/pom.xml new file mode 100644 index 00000000..69b310d5 --- /dev/null +++ b/example/VotingAppJar/VotingAppJar/pom.xml @@ -0,0 +1,30 @@ + + 4.0.0 + + org.onap.music + VotingAppJar + 0.0.1-SNAPSHOT + jar + + VotingAppJar + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 3.8.1 + test + + + org.onap.music + MUSIC + 3.0.2 + + + diff --git a/example/VotingAppJar/VotingAppJar/src/main/java/org/onap/music/VotingAppJar/VotingAppJar.java b/example/VotingAppJar/VotingAppJar/src/main/java/org/onap/music/VotingAppJar/VotingAppJar.java new file mode 100644 index 00000000..ad2661ec --- /dev/null +++ b/example/VotingAppJar/VotingAppJar/src/main/java/org/onap/music/VotingAppJar/VotingAppJar.java @@ -0,0 +1,115 @@ +package org.onap.music.VotingAppJar; + +import java.util.HashMap; +import java.util.Map; + +import org.onap.music.datastore.PreparedQueryObject; +import org.onap.music.exceptions.MusicLockingException; +import org.onap.music.exceptions.MusicQueryException; +import org.onap.music.exceptions.MusicServiceException; +import org.onap.music.main.MusicCore; + +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; + +/** + * + */ +public class VotingAppJar +{ + String keyspaceName; + String tableName; + + public VotingAppJar() throws MusicServiceException { + keyspaceName = "VotingAppForMusic"+System.currentTimeMillis(); + tableName = "votecount"; + + createVotingKeyspace(); + System.out.println("Created keyspaces"); + createVotingTable(); + System.out.println("Created tables"); + + createEntryForCandidate("Popeye"); + createEntryForCandidate("Judy"); + createEntryForCandidate("Flash"); + createEntryForCandidate("Mickey"); + System.out.println("Created candidates"); + } + + private void createVotingKeyspace() throws MusicServiceException { + + Map replicationInfo = new HashMap(); + replicationInfo.put("'class'", "'SimpleStrategy'"); + replicationInfo.put("'replication_factor'", 1); + + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "CREATE KEYSPACE " + keyspaceName + " WITH REPLICATION = " + replicationInfo.toString().replaceAll("=", ":")); + + try { + MusicCore.nonKeyRelatedPut(queryObject, "eventual"); + } catch (MusicServiceException e) { + if (e.getMessage().equals("Keyspace votingappformusic already exists")) { + // ignore + } else { + throw(e); + } + } + } + + private void createVotingTable() throws MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "CREATE TABLE " + keyspaceName + "." + tableName + " (name text PRIMARY KEY, count varint);"); + + try { + MusicCore.createTable(keyspaceName, tableName, queryObject, "eventual"); + } catch (MusicServiceException e) { + if (e.getMessage().equals("Table votingappformusic.votevount already exists")) { + //ignore + } else { + throw(e); + } + } + } + + private void createEntryForCandidate(String candidateName) throws MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "INSERT INTO " + keyspaceName + "." + tableName + " (name, count) " + + "VALUES ('"+candidateName+"', 0);"); + + MusicCore.nonKeyRelatedPut(queryObject, "eventual"); + } + + public void vote() throws MusicLockingException, MusicQueryException, MusicServiceException { + updateVoteCount("Popeye",5); + updateVoteCount("Judy",7); + updateVoteCount("Mickey",8); + updateVoteCount("Flash",2); + } + + private void updateVoteCount(String candidateName, int numVotes) throws MusicLockingException, MusicQueryException, MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString( + "INSERT INTO " + keyspaceName + "." + tableName + " (name, count) " + + "VALUES ('"+candidateName+"', "+numVotes+");"); + MusicCore.atomicPut(keyspaceName, tableName, candidateName, queryObject, null); + } + + private void readAllVotes() throws MusicServiceException { + PreparedQueryObject queryObject = new PreparedQueryObject(); + queryObject.appendQueryString("SELECT * FROM " + keyspaceName + "." + tableName); + ResultSet rs = MusicCore.get(queryObject); + for(Row candidate : rs.all()) { + System.out.println(candidate.getString("name") + " - " + candidate.getVarint("count")); + } + } + + public static void main( String[] args ) throws Exception { + VotingAppJar vHandle = new VotingAppJar(); + vHandle.vote(); + vHandle.readAllVotes(); + } + +} \ No newline at end of file diff --git a/example/VotingAppJar/VotingAppJar/src/test/java/org/onap/music/VotingAppJar/AppTest.java b/example/VotingAppJar/VotingAppJar/src/test/java/org/onap/music/VotingAppJar/AppTest.java new file mode 100644 index 00000000..536655c2 --- /dev/null +++ b/example/VotingAppJar/VotingAppJar/src/test/java/org/onap/music/VotingAppJar/AppTest.java @@ -0,0 +1,38 @@ +package org.onap.music.VotingAppJar; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Unit test for simple App. + */ +public class AppTest + extends TestCase +{ + /** + * Create the test case + * + * @param testName name of the test case + */ + public AppTest( String testName ) + { + super( testName ); + } + + /** + * @return the suite of tests being tested + */ + public static Test suite() + { + return new TestSuite( AppTest.class ); + } + + /** + * Rigourous Test :-) + */ + public void testApp() + { + assertTrue( true ); + } +} -- cgit 1.2.3-korg