summaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authorarthurdent3 <tn1381@att.com>2018-02-02 21:19:53 -0500
committerarthurdent3 <tn1381@att.com>2018-02-05 10:20:49 -0500
commite99b7fa829bf957c2a46223a1a20a32aebeda91b (patch)
tree59ea8681b4165df7fb2482af3f6d411115e32f5a /src/main
parentd221feba08b6ad24e7d232247306f7b67934941d (diff)
Initial code Import.
Issue-ID: MUSIC-21 Change-Id: I89ceab0891b4b7cb999dab532d6bae9092f027cc Signed-off-by: arthurdent3 <tn1381@att.com>
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/LICENSE.txt24
-rw-r--r--src/main/java/org/onap/music/client/MusicClient.java604
-rw-r--r--src/main/java/org/onap/music/client/MusicRestClient.java384
-rw-r--r--src/main/java/org/onap/music/datastore/MusicDataStore.java391
-rw-r--r--src/main/java/org/onap/music/datastore/PreparedQueryObject.java79
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/AAFResponse.java42
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/JsonDelete.java83
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/JsonInsert.java118
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/JsonKeySpace.java73
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/JsonLeasedLock.java49
-rwxr-xr-xsrc/main/java/org/onap/music/datastore/jsonobjects/JsonOnboard.java80
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/JsonSelect.java56
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/JsonTable.java113
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/JsonUpdate.java128
-rw-r--r--src/main/java/org/onap/music/datastore/jsonobjects/NameSpace.java47
-rw-r--r--src/main/java/org/onap/music/eelf/logging/EELFLoggerDelegate.java354
-rw-r--r--src/main/java/org/onap/music/exceptions/MusicLockingException.java74
-rw-r--r--src/main/java/org/onap/music/exceptions/MusicPolicyVoilationException.java79
-rw-r--r--src/main/java/org/onap/music/exceptions/MusicQueryException.java89
-rw-r--r--src/main/java/org/onap/music/exceptions/MusicServiceException.java84
-rw-r--r--src/main/java/org/onap/music/lockingservice/LockListener.java39
-rw-r--r--src/main/java/org/onap/music/lockingservice/MusicLockState.java126
-rw-r--r--src/main/java/org/onap/music/lockingservice/MusicLockingService.java142
-rw-r--r--src/main/java/org/onap/music/lockingservice/ProtocolSupport.java205
-rw-r--r--src/main/java/org/onap/music/lockingservice/ZNodeName.java117
-rw-r--r--src/main/java/org/onap/music/lockingservice/ZkStatelessLockService.java334
-rw-r--r--src/main/java/org/onap/music/lockingservice/ZooKeeperOperation.java42
-rwxr-xr-xsrc/main/java/org/onap/music/main/CachingUtil.java370
-rw-r--r--src/main/java/org/onap/music/main/CronJobManager.java47
-rw-r--r--src/main/java/org/onap/music/main/MusicCore.java874
-rw-r--r--src/main/java/org/onap/music/main/MusicDigest.java78
-rwxr-xr-xsrc/main/java/org/onap/music/main/MusicUtil.java465
-rwxr-xr-xsrc/main/java/org/onap/music/main/PropertiesListener.java147
-rw-r--r--src/main/java/org/onap/music/main/ResultType.java39
-rw-r--r--src/main/java/org/onap/music/main/ReturnType.java74
-rw-r--r--src/main/java/org/onap/music/response/jsonobjects/JsonLockResponse.java258
-rw-r--r--src/main/java/org/onap/music/response/jsonobjects/JsonResponse.java95
-rwxr-xr-xsrc/main/java/org/onap/music/rest/RestMusicAdminAPI.java305
-rw-r--r--src/main/java/org/onap/music/rest/RestMusicBmAPI.java313
-rwxr-xr-xsrc/main/java/org/onap/music/rest/RestMusicDataAPI.java1088
-rw-r--r--src/main/java/org/onap/music/rest/RestMusicLocksAPI.java209
-rwxr-xr-xsrc/main/java/org/onap/music/rest/RestMusicQAPI.java257
-rw-r--r--src/main/java/org/onap/music/rest/RestMusicTestAPI.java67
-rw-r--r--src/main/java/org/onap/music/rest/RestMusicVersionAPI.java61
-rw-r--r--src/main/resources/LICENSE.txt24
-rw-r--r--src/main/resources/Resources.properties49
-rw-r--r--src/main/resources/cache.ccf56
-rw-r--r--src/main/resources/logback.xml269
-rw-r--r--src/main/resources/project.properties4
49 files changed, 9105 insertions, 0 deletions
diff --git a/src/main/java/LICENSE.txt b/src/main/java/LICENSE.txt
new file mode 100644
index 00000000..cc6cdea5
--- /dev/null
+++ b/src/main/java/LICENSE.txt
@@ -0,0 +1,24 @@
+
+The following license applies to all files in this and sub-directories. Licenses
+are included in individual source files where appropriate, and if it differs
+from this text, it supersedes this. Any file that does not have license text
+defaults to being covered by this text; not all files support the addition of
+licenses.
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2017 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.
+#
+# -------------------------------------------------------------------------
+# \ No newline at end of file
diff --git a/src/main/java/org/onap/music/client/MusicClient.java b/src/main/java/org/onap/music/client/MusicClient.java
new file mode 100644
index 00000000..2d29e236
--- /dev/null
+++ b/src/main/java/org/onap/music/client/MusicClient.java
@@ -0,0 +1,604 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.client;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.onap.music.datastore.jsonobjects.JsonInsert;
+import org.onap.music.datastore.jsonobjects.JsonKeySpace;
+import org.onap.music.datastore.jsonobjects.JsonTable;
+import org.onap.music.lockingservice.MusicLockingService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.ColumnDefinitions;
+import com.datastax.driver.core.ColumnDefinitions.Definition;
+import com.datastax.driver.core.ConsistencyLevel;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.KeyspaceMetadata;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.SimpleStatement;
+import com.datastax.driver.core.Statement;
+import com.datastax.driver.core.TableMetadata;
+import com.datastax.driver.core.querybuilder.Clause;
+import com.datastax.driver.core.querybuilder.Delete;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.datastax.driver.core.querybuilder.Select;
+
+/**
+ * A MUSIC client that talks directly to Cassandra/ZooKeeper. This was taken, and slightly modified,
+ * from the REST version of the code.
+ *
+ * @author Robert Eby
+ */
+public class MusicClient {
+ private static final Logger LOG = LoggerFactory.getLogger(MusicClient.class);
+
+ private final String[] music_hosts; // array of hosts in the music cluster
+ private Cluster cluster; // MUSIC Cassandra cluster
+ private Session session; // MUSIC Cassandra session
+ private MusicLockingService mls; // ZooKeeper
+ private final Set<String> lockNames;// set of active lock names
+
+ /**
+ * Create a MUSIC client that talks to MUSIC on localhost.
+ */
+ public MusicClient() {
+ this("127.0.0.1");
+ }
+
+ /**
+ * Create a MUSIC client that talks to MUSIC on a remote host. The string <i>hosts</i> is a
+ * comma-separated list of IP addresses for remote instances of Cassandra/ZooKeeper.
+ *
+ * @param hosts the list of hostnames
+ */
+ public MusicClient(String hosts) {
+ music_hosts = hosts.split(",");
+ if (cluster == null) {
+ LOG.debug("Initializing MUSIC Client with endpoints " + hosts);
+ cluster = Cluster.builder().addContactPoints(music_hosts).build();
+ }
+ session = cluster.connect();
+ mls = null;
+ lockNames = new HashSet<String>();
+ }
+
+ /**
+ * Close the connection to MUSIC.
+ */
+ public void close() {
+ if (session != null) {
+ session.close();
+ session = null;
+ }
+ if (cluster != null) {
+ cluster.close();
+ cluster = null;
+ }
+ }
+
+ /**
+ * Be sure to close the connection to MUSIC when this object is GC-ed.
+ */
+ @Override
+ protected void finalize() {
+ close();
+ }
+
+ /**
+ * Return a String representation of the music hosts used by this object.
+ *
+ * @return the string
+ */
+ @Override
+ public String toString() {
+ List<String> t = Arrays.asList(music_hosts);
+ return "MUSIC hosts=" + t.toString();
+ }
+
+ /**
+ * Create a lock.
+ *
+ * @see org.onap.music.lockingservice.MusicLockingService#createLock(String)
+ * @param lockName the lock name
+ * @return FILL IN
+ */
+ public String createLock(String lockName) {
+ String ln = "/" + lockName;
+ synchronized (lockNames) {
+ lockNames.add(ln);
+ }
+ return getLockingService().createLockId(ln);
+ }
+
+ /**
+ * Acquire a lock.
+ *
+ * @see org.onap.music.lockingservice.MusicLockingService#lock(String)
+ * @param lockName the lock name
+ * @return FILL IN
+ */
+ public boolean acquireLock(String lockName) {
+ return getLockingService().isMyTurn(lockName);
+ }
+
+ /**
+ * Get the lock holder.
+ *
+ * @see org.onap.music.lockingservice.MusicLockingService#currentLockHolder(String)
+ * @param lockName the lock name
+ * @return FILL IN
+ */
+ public String getLockHolder(String lockName) {
+ return getLockingService().whoseTurnIsIt("/" + lockName);
+ }
+
+ /**
+ * Unlock a lock.
+ *
+ * @see org.onap.music.lockingservice.MusicLockingService#unlock(String)
+ * @param lockName the lock name
+ */
+ public void unlockLock(String lockName) {
+ getLockingService().unlockAndDeleteId(lockName);
+ }
+
+ /**
+ * Delete a lock.
+ *
+ * @see org.onap.music.lockingservice.MusicLockingService#deleteLock(String)
+ * @param lockName the lock name
+ */
+ public void deleteLock(String lockName) {
+ String ln = "/" + lockName;
+ synchronized (lockNames) {
+ lockNames.remove(ln);
+ }
+ getLockingService().deleteLock(ln);
+ }
+
+ /**
+ * Delete all locks.
+ *
+ * @see org.onap.music.lockingservice.MusicLockingService#deleteLock(String)
+ * @return true
+ */
+ public boolean deleteAllLocks() {
+ synchronized (lockNames) {
+ for (String lockName : lockNames) {
+ deleteLock(lockName);
+ }
+ lockNames.clear();
+ }
+ return true;
+ }
+
+ /**
+ * Create a keyspace using the default replication configuration.
+ *
+ * @param keyspaceName the name of the keyspace
+ * @return always true currently
+ * @throws Exception Cassandra exceptions are passed through
+ */
+ public boolean createKeyspace(String keyspaceName) throws Exception {
+ Map<String, Object> repl = new HashMap<String, Object>();
+ repl.put("class", "SimpleStrategy");
+ repl.put("replication_factor", 1);
+ Map<String, String> consistencyInfo = Collections.singletonMap("type", "eventual");
+ JsonKeySpace jsonKp = new JsonKeySpace();
+ jsonKp.setConsistencyInfo(consistencyInfo);
+ jsonKp.setDurabilityOfWrites("true");
+ jsonKp.setReplicationInfo(repl);
+ return createKeyspace(keyspaceName, jsonKp);
+ }
+
+ public boolean createKeyspace(String keyspaceName, JsonKeySpace kspObject) throws Exception {
+ String consistency = extractConsistencyInfo(keyspaceName, kspObject.getConsistencyInfo());
+ Map<String, Object> replicationInfo = kspObject.getReplicationInfo();
+ String durability = "";
+ if (kspObject.getDurabilityOfWrites() != null)
+ durability = " AND durable_writes = " + kspObject.getDurabilityOfWrites();
+ String query = String.format(
+ "CREATE KEYSPACE IF NOT EXISTS %s WITH replication = { %s } %s;",
+ keyspaceName, jsonMaptoSqlString(replicationInfo, ","), durability);
+ LOG.debug(query);
+ executeCreateQuery(query, consistency);
+ return true;
+ }
+
+ public boolean dropKeyspace(String keyspaceName, JsonKeySpace kspObject) throws Exception {
+ String consistency = extractConsistencyInfo(keyspaceName, kspObject.getConsistencyInfo());
+ String query = String.format("DROP KEYSPACE %s;", keyspaceName);
+ LOG.debug(query);
+ executeCreateQuery(query, consistency);
+ return false;
+ }
+
+ public boolean createTable(String tablename, Map<String, String> cols) throws Exception {
+ JsonTable tableObj = new JsonTable();
+ Map<String, String> map = new HashMap<String, String>(); // This should be in the
+ // consutructor!
+ map.put("type", "eventual");
+ tableObj.setConsistencyInfo(map);
+ return createTable(tablename, cols, tableObj);
+ }
+
+ public boolean createTable(String tablename, Map<String, String> cols, JsonTable tableObj)
+ throws Exception {
+ // Note: https://docs.datastax.com/en/cql/3.0/cql/cql_reference/create_table_r.html
+
+ // first read the information about the table fields
+ StringBuilder fields = new StringBuilder();
+ String prefix = "";
+ for (String key : cols.keySet()) {
+ fields.append(prefix).append(key).append(" ").append(cols.get(key));
+ prefix = ", ";
+ }
+
+ // information about the name-value style properties
+ // Map<String,Object> propertiesMap = tableObj.getProperties();
+ // String propertiesString="";
+ // if(propertiesMap != null){
+ // counter =0;
+ // for (Map.Entry<String, Object> entry : propertiesMap.entrySet())
+ // {
+ // Object ot = entry.getValue();
+ // String value = ot+"";
+ // if(ot instanceof String){
+ // value = "'"+value+"'";
+ // }else if(ot instanceof Map){
+ // Map<String,Object> otMap = (Map<String,Object>)ot;
+ // value = "{"+jsonMaptoSqlString(otMap, ",")+"}";
+ // }
+ // propertiesString = propertiesString+entry.getKey()+"="+ value+"";
+ // if(counter!=propertiesMap.size()-1)
+ // propertiesString = propertiesString+" AND ";
+ // counter = counter +1;
+ // }
+ // }
+
+ String query = String.format("CREATE TABLE IF NOT EXISTS %s (%s);", tablename,
+ fields.toString());
+ // if (propertiesMap != null)
+ // query = query + " WITH "+ propertiesString;
+
+ LOG.debug(query);
+ String consistency = extractConsistencyInfo(tablename, tableObj.getConsistencyInfo());
+ executeCreateQuery(query, consistency);
+ return false;
+ }
+
+ public boolean dropTable(String name) {
+ // TODO
+ return false;
+ }
+
+ public boolean insertRow(String name, Map<String, Object> valuesMap) throws Exception {
+ Map<String, String> consistencyInfo = Collections.singletonMap("type", "eventual");
+ return insertRow(name, valuesMap, consistencyInfo, new JsonInsert());
+ }
+
+ public boolean insertRow(String tablename, Map<String, Object> valuesMap,
+ Map<String, String> consistencyInfo, JsonInsert insObj) throws Exception {
+ // Note: https://docs.datastax.com/en/cql/3.0/cql/cql_reference/insert_r.html
+ String[] parts = tablename.split("\\.");
+ KeyspaceMetadata ks = cluster.getMetadata().getKeyspace(parts[0]);
+ TableMetadata tableInfo = ks.getTable(parts[1]);
+
+ StringBuilder fields = new StringBuilder();
+ StringBuilder values = new StringBuilder();
+ String prefix = "";
+ for (String key : valuesMap.keySet()) {
+ fields.append(prefix).append(key);
+ Object valueObj = valuesMap.get(key);
+ DataType colType = tableInfo.getColumn(key).getType();
+ values.append(prefix).append(convertToSqlDataType(colType, valueObj));
+ prefix = ", ";
+ }
+
+ String suffix = getTTLSuffix(insObj);
+ String query = String.format("INSERT INTO %s (%s) VALUES (%s)%s;", tablename,
+ fields.toString(), values.toString(), suffix);
+ LOG.debug(query);
+
+ String consistency = extractConsistencyInfo(tablename, consistencyInfo);
+ executeCreateQuery(query, consistency);
+ return false;
+ }
+
+ public boolean lockRow(String name, Map<String, String> cols) {
+ // TODO
+ return false;
+ }
+
+ /**
+ * Select ALL rows in the table.
+ *
+ * @param tablename the name of the table
+ * @return a list of maps, one map per row
+ */
+ public List<Map<String, Object>> selectRows(final String tablename) {
+ return selectRows(tablename, new HashMap<String, String>());
+ }
+
+ public List<Map<String, Object>> selectRows(final String tablename, Map<String, String> cols) {
+ String ns = "";
+ String tbl = tablename;
+ int ix = tbl.indexOf('.');
+ if (ix >= 0) {
+ ns = tablename.substring(0, ix);
+ tbl = tablename.substring(ix + 1);
+ }
+ Select sel = QueryBuilder.select().all().from(ns, tbl);
+ Statement stmt = sel;
+ if (cols.size() == 1) {
+ // only handles 1 WHERE value right now
+ String k = cols.keySet().iterator().next();
+ Clause eqclause = QueryBuilder.eq(k, cols.get(k));
+ stmt = sel.where(eqclause);
+ }
+ ResultSet resultset = session.execute(stmt);
+ List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
+ for (Row row : resultset) {
+ Map<String, Object> map = new HashMap<String, Object>();
+ for (Definition definition : row.getColumnDefinitions()) {
+ map.put(definition.getName(),
+ readRow(row, definition.getName(), definition.getType()));
+ }
+ results.add(map);
+ }
+ return results;
+ }
+
+ private Object readRow(final Row row, final String name, final DataType colType) {
+ switch (colType.getName()) {
+ case BIGINT:
+ return row.getLong(name);
+ case BOOLEAN:
+ return row.getBool(name);
+ case DOUBLE:
+ return row.getDouble(name);
+ case FLOAT:
+ return row.getFloat(name);
+ case INT:
+ return row.getInt(name);
+ case MAP:
+ return row.getMap(name, String.class, String.class);
+ case UUID:
+ return row.getUUID(name);
+ case TEXT:
+ case VARCHAR:
+ return row.getString(name);
+ case VARINT:
+ return row.getVarint(name);
+ // These are not supported right now....
+ // ASCII
+ // BLOB
+ // COUNTER
+ // CUSTOM
+ // DECIMAL
+ // INET
+ // LIST
+ // SET
+ // TIMESTAMP
+ // TIMEUUID
+ // TUPLE
+ // UDT
+ default:
+ return null;
+ }
+ }
+
+ @Deprecated
+ public List<Map<String, String>> OLDselectRows(String tablename, Map<String, String> cols) {
+ String query = String.format("SELECT * FROM %s", tablename);
+ if (cols.size() > 0) {
+ // add WHERE clause
+ // String[] parts = tablename.split("\\.");
+ // KeyspaceMetadata ks = cluster.getMetadata().getKeyspace(parts[0]);
+ // TableMetadata tableInfo = ks.getTable(parts[1]);
+ String whereclause = " WHERE";
+ String prefix = "";
+ for (String key : cols.keySet()) {
+ String val = cols.get(key);
+ // DataType colType = tableInfo.getColumn(key).getType();
+ whereclause = String.format("%s%s %s = '%s'", whereclause, prefix, key, val);
+ prefix = " AND";
+ }
+ query += whereclause;
+ }
+ LOG.debug(query);
+ ResultSet resultset = session.execute(query);
+ List<Map<String, String>> results = new ArrayList<Map<String, String>>();
+ for (Row row : resultset) {
+ ColumnDefinitions colInfo = row.getColumnDefinitions();
+ Map<String, String> map = new HashMap<String, String>();
+ for (Definition definition : colInfo) {
+ // map.put(definition.getName(), (String)MusicDataStore.readRow(row,
+ // definition.getName(), definition.getType()));
+ }
+ results.add(map);
+ }
+ return results;
+ }
+
+ public void updateRows(String tablename, Map<String, String> cols, Map<String, Object> vals)
+ throws Exception {
+ Map<String, String> consistencyInfo = Collections.singletonMap("type", "eventual");
+ updateRows(tablename, cols, vals, consistencyInfo, new JsonInsert());
+ }
+
+ public void updateRows(String tablename, Map<String, String> cols, Map<String, Object> vals,
+ Map<String, String> consistencyInfo, JsonInsert insObj) throws Exception {
+ // https://docs.datastax.com/en/cql/3.0/cql/cql_reference/update_r.html
+
+ // obtain the field value pairs of the update
+ String[] parts = tablename.split("\\.");
+ KeyspaceMetadata ks = cluster.getMetadata().getKeyspace(parts[0]);
+ TableMetadata tableInfo = ks.getTable(parts[1]);
+
+ StringBuilder fields = new StringBuilder();
+ String prefix = "";
+ for (String key : vals.keySet()) {
+ Object valueObj = vals.get(key);
+ String valueString = convertToSqlDataType(tableInfo.getColumn(key).getType(), valueObj);
+ fields.append(prefix).append(key).append(" = ").append(valueString);
+ prefix = ", ";
+ }
+
+ // get the row specifier
+ StringBuilder rows = new StringBuilder();
+ String primaryKey = "";
+ prefix = "";
+ for (String key : cols.keySet()) {
+ String indValue = cols.get(key);
+ DataType colType = tableInfo.getColumn(key).getType();
+ String formattedValue = convertToSqlDataType(colType, indValue);
+ primaryKey = primaryKey + indValue;
+ rows.append(prefix).append(key).append(" = ").append(formattedValue);
+ prefix = " AND ";
+ }
+
+ String using = getTTLSuffix(insObj);
+ String query = String.format("UPDATE %s%s SET %s WHERE %s;", tablename, using,
+ fields.toString(), rows.toString());
+ LOG.debug(query);
+
+ String consistency = extractConsistencyInfo(tablename, consistencyInfo);
+ executeCreateQuery(query, consistency);
+ }
+
+ public void deleteRows(String tablename, Map<String, String> cols) {
+ String ns = "";
+ String tbl = tablename;
+ int ix = tbl.indexOf('.');
+ if (ix >= 0) {
+ ns = tablename.substring(0, ix);
+ tbl = tablename.substring(ix + 1);
+ }
+ Delete stmt = QueryBuilder.delete().from(ns, tbl);
+ if (cols.size() == 1) {
+ // only handles 1 WHERE value right now
+ String k = cols.keySet().iterator().next();
+ Clause eqclause = QueryBuilder.eq(k, cols.get(k));
+ session.execute(stmt.where(eqclause));
+ } else {
+ session.execute(stmt);
+ }
+ }
+
+ private String getTTLSuffix(JsonInsert insObj) {
+ String ttl = insObj.getTtl();
+ String timestamp = insObj.getTimestamp();
+ if (ttl != null && ttl.length() > 0) {
+ if (timestamp != null && timestamp.length() > 0) {
+ return " USING TTL " + ttl + " AND TIMESTAMP " + timestamp;
+ } else {
+ return " USING TTL " + ttl;
+ }
+ } else if (timestamp != null && timestamp.length() > 0) {
+ return " USING TIMESTAMP " + timestamp;
+ }
+ return "";
+ }
+
+ private MusicLockingService getLockingService() {
+ if (mls == null) {
+ mls = new MusicLockingService(music_hosts[0]);
+ }
+ return mls;
+ }
+
+ private String extractConsistencyInfo(String key, Map<String, String> consistencyInfo)
+ throws Exception {
+ String consistency = "";
+ if (consistencyInfo.get("type").equalsIgnoreCase("atomic")) {
+ String lockId = consistencyInfo.get("lockId");
+ String lockName = lockId.substring(lockId.indexOf("$") + 1);
+ lockName = lockName.substring(0, lockName.indexOf("$"));
+
+ // first ensure that the lock name is correct before seeing if it has access
+ if (!lockName.equalsIgnoreCase(key))
+ throw new Exception("THIS LOCK IS NOT FOR THE KEY: " + key);
+
+ String lockStatus = getLockingService().isMyTurn(lockId) + "";
+ if (lockStatus.equalsIgnoreCase("false"))
+ throw new Exception("YOU DO NOT HAVE THE LOCK");
+ return "atomic";
+ }
+ if (consistencyInfo.get("type").equalsIgnoreCase("eventual"))
+ return "eventual";
+ throw new Exception("Consistency type " + consistency + " unknown!!");
+ }
+
+ // utility function to parse json map into sql like string
+ private String jsonMaptoSqlString(Map<String, Object> jMap, String lineDelimiter) {
+ String sql = "";
+ String prefix = "";
+ for (Map.Entry<String, Object> entry : jMap.entrySet()) {
+ Object ot = entry.getValue();
+ String value = ot + "";
+ if (ot instanceof String) {
+ value = "'" + value + "'";
+ }
+ sql = String.format("%s%s'%s': %s", sql, prefix, entry.getKey(), value);
+ prefix = lineDelimiter;
+ }
+ return sql;
+ }
+
+ private String convertToSqlDataType(DataType type, Object valueObj) {
+ switch (type.getName()) {
+ case TEXT:
+ String t = valueObj.toString();
+ t = t.replaceAll("'", "''");
+ return "'" + t + "'";
+ case MAP:
+ @SuppressWarnings("unchecked")
+ Map<String, Object> otMap = (Map<String, Object>) valueObj;
+ return "{" + jsonMaptoSqlString(otMap, ",") + "}";
+ default:
+ case UUID:
+ return valueObj.toString();
+ }
+ }
+
+ private void executeCreateQuery(String query, String consistency) throws Exception {
+ Statement statement = new SimpleStatement(query);
+ if (consistency.equalsIgnoreCase("atomic"))
+ statement.setConsistencyLevel(ConsistencyLevel.ALL);
+ else if (consistency.equalsIgnoreCase("eventual"))
+ statement.setConsistencyLevel(ConsistencyLevel.ONE);
+ else
+ throw new Exception("Consistency level " + consistency + " unknown!!");
+ session.execute(statement);
+ }
+}
diff --git a/src/main/java/org/onap/music/client/MusicRestClient.java b/src/main/java/org/onap/music/client/MusicRestClient.java
new file mode 100644
index 00000000..93a2e12b
--- /dev/null
+++ b/src/main/java/org/onap/music/client/MusicRestClient.java
@@ -0,0 +1,384 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.client;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import javax.ws.rs.core.MediaType;
+import org.onap.music.datastore.jsonobjects.JsonDelete;
+import org.onap.music.datastore.jsonobjects.JsonInsert;
+import org.onap.music.datastore.jsonobjects.JsonKeySpace;
+import org.onap.music.datastore.jsonobjects.JsonTable;
+import org.onap.music.main.MusicUtil;
+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.config.ClientConfig;
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.api.json.JSONConfiguration;
+
+public class MusicRestClient {
+ String[] musicNodes;
+
+ public MusicRestClient(String[] musicNodes) {
+ this.musicNodes = musicNodes;
+ }
+
+ public MusicRestClient(String oneMusicNode) {
+ musicNodes = new String[1];
+ this.musicNodes[0] = oneMusicNode;
+ }
+
+ public String getMusicNodeURL() {
+ String musicurl = "http://" + getMusicNodeIp() + ":8080/MUSIC/rest";
+ return musicurl;
+ }
+
+ private String getMusicNodeIp() {
+ Random r = new Random();
+ int index = r.nextInt(musicNodes.length);
+ return musicNodes[index];
+ }
+
+ public void createKeyspace(String keyspaceName) {
+ Map<String, Object> replicationInfo = new HashMap<String, Object>();
+ replicationInfo.put("class", "SimpleStrategy");
+ replicationInfo.put("replication_factor", 1);
+ String durabilityOfWrites = "false";
+ Map<String, String> consistencyInfo = new HashMap<String, String>();
+ consistencyInfo.put("type", "eventual");
+ org.onap.music.datastore.jsonobjects.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(getMusicNodeURL() + "/keyspaces/" + keyspaceName);
+
+ ClientResponse response = webResource.accept("application/json").type("application/json")
+ .post(ClientResponse.class, jsonKp);
+
+ if (response.getStatus() < 200 || response.getStatus() > 299)
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+
+ }
+
+ public void createStringMapTable(String keyspaceName, String tableName,
+ Map<String, String> fields) {
+ Map<String, String> consistencyInfo = new HashMap<String, String>();
+ 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 = getMusicNodeURL() + "/keyspaces/" + keyspaceName + "/tables/" + tableName;
+ WebResource webResource = client.resource(url);
+
+ ClientResponse response = webResource.accept("application/json").type("application/json")
+ .post(ClientResponse.class, jtab);
+
+ if (response.getStatus() < 200 || response.getStatus() > 299)
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+
+ }
+
+ public void checkMusicVersion() {
+ Client client = Client.create();
+
+ WebResource webResource = client.resource(getMusicNodeURL() + "/version");
+
+ ClientResponse response = webResource.accept("text/plain").get(ClientResponse.class);
+
+ if (response.getStatus() != 200) {
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+ }
+
+ String output = response.getEntity(String.class);
+ }
+
+ public void createRow(String keyspaceName, String tableName, Map<String, Object> values) {
+ Map<String, String> consistencyInfo = new HashMap<String, String>();
+ 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 = getMusicNodeURL() + "/keyspaces/" + keyspaceName + "/tables/" + tableName
+ + "/rows";
+ WebResource webResource = client.resource(url);
+
+ ClientResponse response = 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 + "values:" + values);
+
+
+ }
+
+ private void basicUpdateRow(String keyspaceName, String tableName, String primaryKeyName,
+ String primaryKeyValue, Map<String, Object> values,
+ Map<String, String> consistencyInfo) {
+ 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 = getMusicNodeURL() + "/keyspaces/" + keyspaceName + "/tables/" + tableName
+ + "/rows?" + primaryKeyName + "=" + primaryKeyValue;
+ WebResource webResource = client.resource(url);
+
+ ClientResponse response = webResource.accept("application/json").type("application/json")
+ .put(ClientResponse.class, jIns);
+
+ if (response.getStatus() < 200 || response.getStatus() > 299)
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus() + "url:"
+ + url + " values:" + values);
+
+ }
+
+ public void updateEntry(String keyspaceName, String tableName, String primaryKeyName,
+ String primaryKeyValue, Map<String, Object> values) {
+ Map<String, String> consistencyInfo = new HashMap<String, String>();
+ consistencyInfo.put("type", "eventual");
+ basicUpdateRow(keyspaceName, tableName, primaryKeyName, primaryKeyValue, values,
+ consistencyInfo);
+ }
+
+ public void deleteEntry(String keyspaceName, String tableName, String primaryKeyName,
+ String primaryKeyValue) {
+ Map<String, String> consistencyInfo = new HashMap<String, String>();
+ 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 = getMusicNodeURL() + "/keyspaces/" + keyspaceName + "/tables/" + tableName
+ + "/rows?" + primaryKeyName + "=" + primaryKeyValue;
+ WebResource webResource = client.resource(url);
+
+ ClientResponse response = 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<String, Object> readRow(String keyspaceName, String tableName, String primaryKeyName,
+ String primaryKeyValue) {
+ ClientConfig clientConfig = new DefaultClientConfig();
+
+ clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
+
+ Client client = Client.create(clientConfig);
+ String url = getMusicNodeURL() + "/keyspaces/" + keyspaceName + "/tables/" + tableName
+ + "/rows?" + primaryKeyName + "=" + primaryKeyValue;
+ WebResource webResource = client.resource(url);
+
+ ClientResponse response = webResource.accept("application/json").get(ClientResponse.class);
+
+ if (response.getStatus() < 200 || response.getStatus() > 299)
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+
+ Map<String, Object> output = response.getEntity(Map.class);
+ return output;
+ }
+
+ public Map<String, Object> readAllRows(String keyspaceName, String tableName) {
+ ClientConfig clientConfig = new DefaultClientConfig();
+
+ clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
+
+ Client client = Client.create(clientConfig);
+ String url = getMusicNodeURL() + "/keyspaces/" + keyspaceName + "/tables/" + tableName
+ + "/rows";
+ WebResource webResource = client.resource(url);
+
+ ClientResponse response = webResource.accept("application/json").get(ClientResponse.class);
+
+ if (response.getStatus() < 200 || response.getStatus() > 299)
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+
+ Map<String, Object> output = response.getEntity(Map.class);
+ return output;
+ }
+
+
+ public void dropKeySpace(String keyspaceName) {
+ Map<String, String> consistencyInfo = new HashMap<String, String>();
+ 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(getMusicNodeURL() + "/keyspaces/" + keyspaceName);
+
+ ClientResponse response =
+ webResource.type("application/json").delete(ClientResponse.class, jsonKp);
+
+ if (response.getStatus() < 200 || response.getStatus() > 299)
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+ }
+
+ public String createLock(String primaryKeyValue) {
+ Client client = Client.create();
+ String msg = getMusicNodeURL() + "/locks/create/" + primaryKeyValue;
+ WebResource webResource = client.resource(msg);
+
+ WebResource.Builder wb = webResource.accept(MediaType.TEXT_PLAIN);
+
+ ClientResponse response = wb.post(ClientResponse.class);
+
+ if (response.getStatus() != 200) {
+ throw new RuntimeException(
+ "Failed : HTTP error code : " + response.getStatus() + "url:" + msg);
+ }
+
+ String output = response.getEntity(String.class);
+
+ return output;
+ }
+
+ public boolean acquireLock(String lockId) {
+ Client client = Client.create();
+ String msg = getMusicNodeURL() + "/locks/acquire/" + lockId;
+ WebResource webResource = client.resource(msg);
+
+
+ WebResource.Builder wb = webResource.accept(MediaType.TEXT_PLAIN);
+
+ ClientResponse response = wb.get(ClientResponse.class);
+
+ if (response.getStatus() != 200) {
+ throw new RuntimeException(
+ "Failed : HTTP error code : " + response.getStatus() + "url:" + msg);
+ }
+
+ String output = response.getEntity(String.class);
+ Boolean status = Boolean.parseBoolean(output);
+ return status;
+ }
+
+ public void releaseLock(String lockId) {
+ Client client = Client.create();
+ WebResource webResource = client.resource(getMusicNodeURL() + "/locks/release/" + lockId);
+
+ ClientResponse response = webResource.delete(ClientResponse.class);
+
+
+ if (response.getStatus() != 204) {
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+ }
+ }
+
+
+ public void updateRowAtomically(String keyspaceName, String tableName, String primaryKeyName,
+ String primaryKeyValue, Map<String, Object> values) {
+ /*
+ * create lock for the candidate. The music API dictates that the lock name must be of the
+ * form keyspacename.tableName.primaryKeyName
+ */
+
+ String lockName = keyspaceName + "." + tableName + "." + primaryKeyValue;
+ String lockId = createLock(lockName);
+ while (acquireLock(lockId) != true);
+
+
+ Map<String, String> consistencyInfo = new HashMap<String, String>();
+ consistencyInfo.put("type", "atomic");
+ consistencyInfo.put("lockId", lockId);
+
+ basicUpdateRow(keyspaceName, tableName, primaryKeyName, primaryKeyValue, values,
+ consistencyInfo);
+
+ // release lock now that the operation is done
+ releaseLock(lockId);
+
+ }
+
+ public String getMusicId() {
+
+ Client client = Client.create();
+
+ WebResource webResource = client.resource(getMusicNodeURL() + "/nodeId");
+ ClientResponse response = webResource.accept("text/plain").get(ClientResponse.class);
+
+ if (response.getStatus() != 200) {
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+ }
+
+ String output = response.getEntity(String.class);
+ return output;
+ }
+
+ public void deleteRowAtomically(String keyspaceName, String tableName, String primaryKeyName,
+ String primaryKeyValue, Map<String, Object> values) {
+
+ }
+
+ public void deleteLock(String lockName) {
+ Client client = Client.create();
+ WebResource webResource = client.resource(getMusicNodeURL() + "/locks/delete/" + lockName);
+
+ ClientResponse response = webResource.delete(ClientResponse.class);
+
+
+ if (response.getStatus() != 204) {
+ throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
+ }
+ }
+}
+
diff --git a/src/main/java/org/onap/music/datastore/MusicDataStore.java b/src/main/java/org/onap/music/datastore/MusicDataStore.java
new file mode 100644
index 00000000..c67c72e1
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/MusicDataStore.java
@@ -0,0 +1,391 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.onap.music.exceptions.MusicQueryException;
+import org.onap.music.exceptions.MusicServiceException;
+import org.onap.music.main.MusicUtil;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.datastax.driver.core.Cluster;
+import com.datastax.driver.core.ColumnDefinitions;
+import com.datastax.driver.core.ColumnDefinitions.Definition;
+import com.datastax.driver.core.ConsistencyLevel;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.KeyspaceMetadata;
+import com.datastax.driver.core.Metadata;
+import com.datastax.driver.core.PreparedStatement;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.TableMetadata;
+import com.datastax.driver.core.exceptions.NoHostAvailableException;
+
+/**
+ * @author nelson24
+ *
+ */
+public class MusicDataStore {
+ private Session session;
+ private Cluster cluster;
+
+
+
+ /**
+ * @param session
+ */
+ public void setSession(Session session) {
+ this.session = session;
+ }
+
+ /**
+ * @param cluster
+ */
+ public void setCluster(Cluster cluster) {
+ this.cluster = cluster;
+ }
+
+ /**
+ *
+ */
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(MusicDataStore.class);
+
+ /**
+ *
+ */
+ public MusicDataStore() {
+ connectToCassaCluster();
+ }
+
+
+ /**
+ * @param cluster
+ * @param session
+ */
+ public MusicDataStore(Cluster cluster, Session session) {
+ this.session = session;
+ this.cluster = cluster;
+ }
+
+ /**
+ *
+ * @param remoteIp
+ * @throws MusicServiceException
+ */
+ public MusicDataStore(String remoteIp) {
+ try {
+ connectToCassaCluster(remoteIp);
+ } catch (MusicServiceException e) {
+ logger.error(e.getMessage());
+ }
+ }
+
+ /**
+ *
+ * @return
+ */
+ private ArrayList<String> getAllPossibleLocalIps() {
+ ArrayList<String> allPossibleIps = new ArrayList<String>();
+ try {
+ Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
+ while (en.hasMoreElements()) {
+ NetworkInterface ni = (NetworkInterface) en.nextElement();
+ Enumeration<InetAddress> ee = ni.getInetAddresses();
+ while (ee.hasMoreElements()) {
+ InetAddress ia = (InetAddress) ee.nextElement();
+ allPossibleIps.add(ia.getHostAddress());
+ }
+ }
+ } catch (SocketException e) {
+ logger.error(e.getMessage());
+ }
+ return allPossibleIps;
+ }
+
+ /**
+ * This method iterates through all available IP addresses and connects to multiple cassandra
+ * clusters.
+ */
+ private void connectToCassaCluster() {
+ Iterator<String> it = getAllPossibleLocalIps().iterator();
+ String address = "localhost";
+ logger.info("Connecting to cassa cluster: Iterating through possible ips:"
+ + getAllPossibleLocalIps());
+ while (it.hasNext()) {
+ try {
+ cluster = Cluster.builder().withPort(9042)
+ .withCredentials(MusicUtil.getCassName(), MusicUtil.getCassPwd())
+ .addContactPoint(address).build();
+ Metadata metadata = cluster.getMetadata();
+ logger.info("Connected to cassa cluster " + metadata.getClusterName() + " at "
+ + address);
+ session = cluster.connect();
+
+ break;
+ } catch (NoHostAvailableException e) {
+ address = it.next();
+ logger.error(e.getMessage());
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ public void close() {
+ session.close();
+ }
+
+ /**
+ * This method connects to cassandra cluster on specific address.
+ *
+ * @param address
+ */
+ private void connectToCassaCluster(String address) throws MusicServiceException {
+ cluster = Cluster.builder().withPort(9042)
+ .withCredentials(MusicUtil.getCassName(), MusicUtil.getCassPwd())
+ .addContactPoint(address).build();
+ Metadata metadata = cluster.getMetadata();
+ logger.info("Connected to cassa cluster " + metadata.getClusterName() + " at " + address);
+ try {
+ session = cluster.connect();
+ } catch (Exception ex) {
+ logger.error(ex.getMessage());
+ throw new MusicServiceException(
+ "Error while connecting to Cassandra cluster.. " + ex.getMessage());
+ }
+ }
+
+ /**
+ *
+ * @param keyspace
+ * @param tableName
+ * @param columnName
+ * @return DataType
+ */
+ public DataType returnColumnDataType(String keyspace, String tableName, String columnName) {
+ KeyspaceMetadata ks = cluster.getMetadata().getKeyspace(keyspace);
+ TableMetadata table = ks.getTable(tableName);
+ return table.getColumn(columnName).getType();
+
+ }
+
+ /**
+ *
+ * @param keyspace
+ * @param tableName
+ * @return TableMetadata
+ */
+ public TableMetadata returnColumnMetadata(String keyspace, String tableName) {
+ KeyspaceMetadata ks = cluster.getMetadata().getKeyspace(keyspace);
+ return ks.getTable(tableName);
+ }
+
+
+ /**
+ * Utility function to return the Java specific object type.
+ *
+ * @param row
+ * @param colName
+ * @param colType
+ * @return
+ */
+ public Object getColValue(Row row, String colName, DataType colType) {
+
+ switch (colType.getName()) {
+ case VARCHAR:
+ return row.getString(colName);
+ case UUID:
+ return row.getUUID(colName);
+ case VARINT:
+ return row.getVarint(colName);
+ case BIGINT:
+ return row.getLong(colName);
+ case INT:
+ return row.getInt(colName);
+ case FLOAT:
+ return row.getFloat(colName);
+ case DOUBLE:
+ return row.getDouble(colName);
+ case BOOLEAN:
+ return row.getBool(colName);
+ case MAP:
+ return row.getMap(colName, String.class, String.class);
+ default:
+ return null;
+ }
+ }
+
+ public boolean doesRowSatisfyCondition(Row row, Map<String, Object> condition) {
+ ColumnDefinitions colInfo = row.getColumnDefinitions();
+
+ for (Map.Entry<String, Object> entry : condition.entrySet()) {
+ String colName = entry.getKey();
+ DataType colType = colInfo.getType(colName);
+ Object columnValue = getColValue(row, colName, colType);
+ Object conditionValue = MusicUtil.convertToActualDataType(colType, entry.getValue());
+ if (columnValue.equals(conditionValue) == false)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Utility function to store ResultSet values in to a MAP for output.
+ *
+ * @param results
+ * @return MAP
+ */
+ public Map<String, HashMap<String, Object>> marshalData(ResultSet results) {
+ Map<String, HashMap<String, Object>> resultMap =
+ new HashMap<String, HashMap<String, Object>>();
+ int counter = 0;
+ for (Row row : results) {
+ ColumnDefinitions colInfo = row.getColumnDefinitions();
+ HashMap<String, Object> resultOutput = new HashMap<String, Object>();
+ for (Definition definition : colInfo) {
+ if (!definition.getName().equals("vector_ts"))
+ resultOutput.put(definition.getName(),
+ getColValue(row, definition.getName(), definition.getType()));
+ }
+ resultMap.put("row " + counter, resultOutput);
+ counter++;
+ }
+ return resultMap;
+ }
+
+
+ // Prepared Statements 1802 additions
+ /**
+ * This Method performs DDL and DML operations on Cassandra using specified consistency level
+ *
+ * @param queryObject Object containing cassandra prepared query and values.
+ * @param consistency Specify consistency level for data synchronization across cassandra
+ * replicas
+ * @return Boolean Indicates operation success or failure
+ * @throws MusicServiceException
+ * @throws MusicQueryException
+ */
+ public boolean executePut(PreparedQueryObject queryObject, String consistency)
+ throws MusicServiceException, MusicQueryException {
+
+ boolean result = false;
+
+ if (!MusicUtil.isValidQueryObject(!queryObject.getValues().isEmpty(), queryObject)) {
+ logger.error("Error while processing prepared query object");
+ throw new MusicQueryException("Ill formed queryObject for the request = " + "["
+ + queryObject.getQuery() + "]");
+ }
+ logger.info("In preprared Execute Put: the actual insert query:" + queryObject.getQuery()
+ + "; the values" + queryObject.getValues());
+ PreparedStatement preparedInsert = session.prepare(queryObject.getQuery());
+ try {
+ if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
+ logger.info("Executing critical put query");
+ preparedInsert.setConsistencyLevel(ConsistencyLevel.QUORUM);
+ } else if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
+ logger.info("Executing simple put query");
+ preparedInsert.setConsistencyLevel(ConsistencyLevel.ONE);
+ }
+
+ session.execute(preparedInsert.bind(queryObject.getValues().toArray()));
+ result = true;
+ } catch (Exception e) {
+ logger.error("Executing Session Failure for Request = " + "[" + queryObject.getQuery()
+ + "]" + " Reason = " + e.getMessage());
+ throw new MusicServiceException("Executing Session Failure for Request = " + "["
+ + queryObject.getQuery() + "]" + " Reason = " + e.getMessage());
+ }
+
+
+ return result;
+ }
+
+ /**
+ * This method performs DDL operations on Cassandra using consistency level ONE.
+ *
+ * @param queryObject Object containing cassandra prepared query and values.
+ * @return ResultSet
+ * @throws MusicServiceException
+ * @throws MusicQueryException
+ */
+ public ResultSet executeEventualGet(PreparedQueryObject queryObject)
+ throws MusicServiceException, MusicQueryException {
+
+ if (!MusicUtil.isValidQueryObject(!queryObject.getValues().isEmpty(), queryObject)) {
+ throw new MusicQueryException("Ill formed queryObject for the request = " + "["
+ + queryObject.getQuery() + "]");
+ }
+ logger.info("Executing Eventual get query:" + queryObject.getQuery());
+ PreparedStatement preparedEventualGet = session.prepare(queryObject.getQuery());
+ preparedEventualGet.setConsistencyLevel(ConsistencyLevel.ONE);
+ ResultSet results = null;
+ try {
+ results = session.execute(preparedEventualGet.bind(queryObject.getValues().toArray()));
+
+ } catch (Exception ex) {
+ logger.error(ex.getMessage());
+ throw new MusicServiceException(ex.getMessage());
+ }
+ return results;
+ }
+
+ /**
+ *
+ * This method performs DDL operation on Cassandra using consistency level QUORUM.
+ *
+ * @param queryObject Object containing cassandra prepared query and values.
+ * @return ResultSet
+ * @throws MusicServiceException
+ * @throws MusicQueryException
+ */
+ public ResultSet executeCriticalGet(PreparedQueryObject queryObject)
+ throws MusicServiceException, MusicQueryException {
+ if (!MusicUtil.isValidQueryObject(!queryObject.getValues().isEmpty(), queryObject)) {
+ logger.error("Error processing Prepared Query Object");
+ throw new MusicQueryException("Ill formed queryObject for the request = " + "["
+ + queryObject.getQuery() + "]");
+ }
+ logger.info("Executing Critical get query:" + queryObject.getQuery());
+ PreparedStatement preparedEventualGet = session.prepare(queryObject.getQuery());
+ preparedEventualGet.setConsistencyLevel(ConsistencyLevel.QUORUM);
+ ResultSet results = null;
+ try {
+ results = session.execute(preparedEventualGet.bind(queryObject.getValues().toArray()));
+ } catch (Exception ex) {
+ logger.error(ex.getMessage());
+ throw new MusicServiceException(ex.getMessage());
+ }
+ return results;
+
+ }
+
+
+}
diff --git a/src/main/java/org/onap/music/datastore/PreparedQueryObject.java b/src/main/java/org/onap/music/datastore/PreparedQueryObject.java
new file mode 100644
index 00000000..694d9acd
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/PreparedQueryObject.java
@@ -0,0 +1,79 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author srupane
+ *
+ */
+public class PreparedQueryObject {
+
+
+ private List<Object> values;
+ private StringBuilder query;
+
+
+
+ /**
+ *
+ */
+ public PreparedQueryObject() {
+
+ this.values = new ArrayList<>();
+ this.query = new StringBuilder();
+ }
+
+ /**
+ * @return
+ */
+ public List<Object> getValues() {
+ return values;
+ }
+
+ /**
+ * @param o
+ */
+ public void addValue(Object o) {
+ this.values.add(o);
+ }
+
+ /**
+ * @param s
+ */
+ public void appendQueryString(String s) {
+ this.query.append(s);
+ }
+
+ /**
+ * @return
+ */
+ public String getQuery() {
+ return this.query.toString();
+ }
+
+
+
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/AAFResponse.java b/src/main/java/org/onap/music/datastore/jsonobjects/AAFResponse.java
new file mode 100644
index 00000000..df6089ee
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/AAFResponse.java
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import java.util.ArrayList;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonTable", description = "Reponse class for AAF request")
+public class AAFResponse {
+
+ private ArrayList<NameSpace> ns = null;
+
+ @ApiModelProperty(value = "Namespace value")
+ public ArrayList<NameSpace> getNs() {
+ return ns;
+ }
+
+ public void setNs(ArrayList<NameSpace> ns) {
+ this.ns = ns;
+ }
+
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/JsonDelete.java b/src/main/java/org/onap/music/datastore/jsonobjects/JsonDelete.java
new file mode 100644
index 00000000..87c000b2
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/JsonDelete.java
@@ -0,0 +1,83 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import java.util.ArrayList;
+import java.util.Map;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonTable", description = "Json model for delete")
+public class JsonDelete {
+
+ private ArrayList<String> columns = null;
+ private Map<String, String> consistencyInfo;
+ private Map<String, Object> conditions;
+ String ttl, timestamp;
+
+
+ @ApiModelProperty(value = "Conditions")
+ public Map<String, Object> getConditions() {
+ return conditions;
+ }
+
+ public void setConditions(Map<String, Object> conditions) {
+ this.conditions = conditions;
+ }
+
+ @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
+ public Map<String, String> getConsistencyInfo() {
+ return consistencyInfo;
+ }
+
+ public void setConsistencyInfo(Map<String, String> consistencyInfo) {
+ this.consistencyInfo = consistencyInfo;
+ }
+
+ @ApiModelProperty(value = "Column values")
+ public ArrayList<String> getColumns() {
+ return columns;
+ }
+
+ public void setColumns(ArrayList<String> columns) {
+ this.columns = columns;
+ }
+
+
+ @ApiModelProperty(value = "Time to live information")
+ public String getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(String ttl) {
+ this.ttl = ttl;
+ }
+
+ @ApiModelProperty(value = "Time stamp")
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(String timestamp) {
+ this.timestamp = timestamp;
+ }
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/JsonInsert.java b/src/main/java/org/onap/music/datastore/jsonobjects/JsonInsert.java
new file mode 100644
index 00000000..22c0104b
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/JsonInsert.java
@@ -0,0 +1,118 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Map;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonTable", description = "Json model for table vlaues insert")
+public class JsonInsert implements Serializable {
+ private String keyspaceName;
+ private String tableName;
+ private Map<String, Object> values;
+ String ttl, timestamp;
+ private Map<String, Object> row_specification;
+ private Map<String, String> consistencyInfo;
+
+ @ApiModelProperty(value = "keyspace")
+ public String getKeyspaceName() {
+ return keyspaceName;
+ }
+
+ public void setKeyspaceName(String keyspaceName) {
+ this.keyspaceName = keyspaceName;
+ }
+
+ @ApiModelProperty(value = "Table name")
+ public String getTableName() {
+ return tableName;
+ }
+
+ public void setTableName(String tableName) {
+ this.tableName = tableName;
+ }
+
+ @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
+ public Map<String, String> getConsistencyInfo() {
+ return consistencyInfo;
+ }
+
+ public void setConsistencyInfo(Map<String, String> consistencyInfo) {
+ this.consistencyInfo = consistencyInfo;
+ }
+
+ @ApiModelProperty(value = "Time to live information")
+ public String getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(String ttl) {
+ this.ttl = ttl;
+ }
+
+ @ApiModelProperty(value = "Time stamp")
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(String timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ @ApiModelProperty(value = "values returned")
+ public Map<String, Object> getValues() {
+ return values;
+ }
+
+ public void setValues(Map<String, Object> values) {
+ this.values = values;
+ }
+
+ @ApiModelProperty(value = "Information for selecting specific rows for insert")
+ public Map<String, Object> getRow_specification() {
+ return row_specification;
+ }
+
+ public void setRow_specification(Map<String, Object> row_specification) {
+ this.row_specification = row_specification;
+ }
+
+ public byte[] serialize() {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutput out = null;
+ try {
+ out = new ObjectOutputStream(bos);
+ out.writeObject(this);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return bos.toByteArray();
+ }
+
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/JsonKeySpace.java b/src/main/java/org/onap/music/datastore/jsonobjects/JsonKeySpace.java
new file mode 100644
index 00000000..01b72672
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/JsonKeySpace.java
@@ -0,0 +1,73 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import java.util.Map;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonTable", description = "Json model creating new keyspace")
+public class JsonKeySpace {
+ private String keyspaceName;
+ private Map<String, Object> replicationInfo;
+ private String durabilityOfWrites;
+ private Map<String, String> consistencyInfo;
+
+ @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
+ public Map<String, String> getConsistencyInfo() {
+ return consistencyInfo;
+ }
+
+ public void setConsistencyInfo(Map<String, String> consistencyInfo) {
+ this.consistencyInfo = consistencyInfo;
+ }
+
+ @ApiModelProperty(value = "Replication information")
+ public Map<String, Object> getReplicationInfo() {
+ return replicationInfo;
+ }
+
+ public void setReplicationInfo(Map<String, Object> replicationInfo) {
+ this.replicationInfo = replicationInfo;
+ }
+
+ @ApiModelProperty(value = "Durability", allowableValues = "true,false")
+ public String getDurabilityOfWrites() {
+ return durabilityOfWrites;
+ }
+
+ public void setDurabilityOfWrites(String durabilityOfWrites) {
+ this.durabilityOfWrites = durabilityOfWrites;
+ }
+
+ @ApiModelProperty(value = "Keyspace name")
+ public String getKeyspaceName() {
+ return keyspaceName;
+ }
+
+ public void setKeyspaceName(String keyspaceName) {
+ this.keyspaceName = keyspaceName;
+ }
+
+
+
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/JsonLeasedLock.java b/src/main/java/org/onap/music/datastore/jsonobjects/JsonLeasedLock.java
new file mode 100644
index 00000000..85895baf
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/JsonLeasedLock.java
@@ -0,0 +1,49 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonTable", description = "model for leased lock")
+public class JsonLeasedLock {
+ long leasePeriod;
+ String notifyUrl;
+
+ @ApiModelProperty(value = "Lease period")
+ public long getLeasePeriod() {
+ return leasePeriod;
+ }
+
+ public void setLeasePeriod(long leasePeriod) {
+ this.leasePeriod = leasePeriod;
+ }
+
+ @ApiModelProperty(value = "URL to be notified")
+ public String getNotifyUrl() {
+ return notifyUrl;
+ }
+
+ public void setNotifyUrl(String notifyUrl) {
+ this.notifyUrl = notifyUrl;
+ }
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/JsonOnboard.java b/src/main/java/org/onap/music/datastore/jsonobjects/JsonOnboard.java
new file mode 100755
index 00000000..11311733
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/JsonOnboard.java
@@ -0,0 +1,80 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonOnboard", description = "Defines the Json for Onboarding an application.")
+public class JsonOnboard {
+ private String appname;
+ private String userId;
+ private String password;
+ private String isAAF;
+ private String aid;
+
+ @ApiModelProperty(value = "Application Password")
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ @ApiModelProperty(value = "Application UUID")
+ public String getAid() {
+ return aid;
+ }
+
+ public void setAid(String aid) {
+ this.aid = aid;
+ }
+
+ @ApiModelProperty(value = "Application name")
+ public String getAppname() {
+ return appname;
+ }
+
+ public void setAppname(String appname) {
+ this.appname = appname;
+ }
+
+ @ApiModelProperty(value = "User Id")
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ @ApiModelProperty(value = "Is AAF Application", allowableValues = "true, false")
+ public String getIsAAF() {
+ return isAAF;
+ }
+
+ public void setIsAAF(String isAAF) {
+ this.isAAF = isAAF;
+ }
+
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/JsonSelect.java b/src/main/java/org/onap/music/datastore/jsonobjects/JsonSelect.java
new file mode 100644
index 00000000..0c2d012c
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/JsonSelect.java
@@ -0,0 +1,56 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Map;
+
+public class JsonSelect implements Serializable {
+ private Map<String, String> consistencyInfo;
+
+
+ public Map<String, String> getConsistencyInfo() {
+ return consistencyInfo;
+ }
+
+ public void setConsistencyInfo(Map<String, String> consistencyInfo) {
+ this.consistencyInfo = consistencyInfo;
+ }
+
+ public byte[] serialize() {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutput out = null;
+ try {
+ out = new ObjectOutputStream(bos);
+ out.writeObject(this);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ return bos.toByteArray();
+ }
+
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/JsonTable.java b/src/main/java/org/onap/music/datastore/jsonobjects/JsonTable.java
new file mode 100644
index 00000000..c0d8521d
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/JsonTable.java
@@ -0,0 +1,113 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import java.util.Map;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonTable", description = "Defines the Json for Creating a new Table.")
+public class JsonTable {
+ private String keyspaceName;
+ private String tableName;
+
+ private Map<String, String> fields;
+ private Map<String, Object> properties;
+ private String primaryKey;
+ private String sortingKey;
+ private String clusteringOrder;
+ private Map<String, String> consistencyInfo;
+
+ @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
+ public Map<String, String> getConsistencyInfo() {
+ return consistencyInfo;
+ }
+
+ public void setConsistencyInfo(Map<String, String> consistencyInfo) {
+ this.consistencyInfo = consistencyInfo;
+ }
+
+ @ApiModelProperty(value = "Properties")
+ public Map<String, Object> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map<String, Object> properties) {
+ this.properties = properties;
+ }
+
+ @ApiModelProperty(value = "Fields")
+ public Map<String, String> getFields() {
+ return fields;
+ }
+
+ public void setFields(Map<String, String> fields) {
+ this.fields = fields;
+ }
+
+ @ApiModelProperty(value = "KeySpace Name")
+ public String getKeyspaceName() {
+ return keyspaceName;
+ }
+
+ public void setKeyspaceName(String keyspaceName) {
+ this.keyspaceName = keyspaceName;
+ }
+
+ @ApiModelProperty(value = "Table Name")
+ public String getTableName() {
+ return tableName;
+ }
+
+ public void setTableName(String tableName) {
+ this.tableName = tableName;
+ }
+
+ @ApiModelProperty(value = "Sorting Key")
+ public String getSortingKey() {
+ return sortingKey;
+ }
+
+ public void setSortingKey(String sortingKey) {
+ this.sortingKey = sortingKey;
+ }
+
+ @ApiModelProperty(value = "Clustering Order", notes = "")
+ public String getClusteringOrder() {
+ return clusteringOrder;
+ }
+
+ public void setClusteringOrder(String clusteringOrder) {
+ this.clusteringOrder = clusteringOrder;
+ }
+
+ @ApiModelProperty(value = "Primary Key")
+ public String getPrimaryKey() {
+ return primaryKey;
+ }
+
+ public void setPrimaryKey(String primaryKey) {
+ this.primaryKey = primaryKey;
+ }
+
+
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/JsonUpdate.java b/src/main/java/org/onap/music/datastore/jsonobjects/JsonUpdate.java
new file mode 100644
index 00000000..fae7720d
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/JsonUpdate.java
@@ -0,0 +1,128 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Map;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonTable", description = "Json model for table update")
+public class JsonUpdate implements Serializable {
+ private String keyspaceName;
+ private String tableName;
+ private Map<String, Object> values;
+ private String ttl, timestamp;
+ private Map<String, String> consistencyInfo;
+ private Map<String, Object> conditions;
+ private Map<String, Object> row_specification;
+
+ @ApiModelProperty(value = "Conditions")
+ public Map<String, Object> getConditions() {
+ return conditions;
+ }
+
+ public void setConditions(Map<String, Object> conditions) {
+ this.conditions = conditions;
+ }
+
+ @ApiModelProperty(value = "Information for selecting sepcific rows")
+ public Map<String, Object> getRow_specification() {
+ return row_specification;
+ }
+
+ public void setRow_specification(Map<String, Object> row_specification) {
+ this.row_specification = row_specification;
+ }
+
+
+ @ApiModelProperty(value = "Keyspace name")
+ public String getKeyspaceName() {
+ return keyspaceName;
+ }
+
+ public void setKeyspaceName(String keyspaceName) {
+ this.keyspaceName = keyspaceName;
+ }
+
+ @ApiModelProperty(value = "Table name")
+ public String getTableName() {
+ return tableName;
+ }
+
+ public void setTableName(String tableName) {
+ this.tableName = tableName;
+ }
+
+ @ApiModelProperty(value = "Consistency level", allowableValues = "eventual,critical,atomic")
+ public Map<String, String> getConsistencyInfo() {
+ return consistencyInfo;
+ }
+
+ public void setConsistencyInfo(Map<String, String> consistencyInfo) {
+ this.consistencyInfo = consistencyInfo;
+ }
+
+ @ApiModelProperty(value = "Time to live value")
+ public String getTtl() {
+ return ttl;
+ }
+
+ public void setTtl(String ttl) {
+ this.ttl = ttl;
+ }
+
+ @ApiModelProperty(value = "Time stamp")
+ public String getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(String timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ @ApiModelProperty(value = "Column values")
+ public Map<String, Object> getValues() {
+ return values;
+ }
+
+ public void setValues(Map<String, Object> values) {
+ this.values = values;
+ }
+
+ public byte[] serialize() {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutput out = null;
+ try {
+ out = new ObjectOutputStream(bos);
+ out.writeObject(this);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return bos.toByteArray();
+ }
+
+}
diff --git a/src/main/java/org/onap/music/datastore/jsonobjects/NameSpace.java b/src/main/java/org/onap/music/datastore/jsonobjects/NameSpace.java
new file mode 100644
index 00000000..232353c1
--- /dev/null
+++ b/src/main/java/org/onap/music/datastore/jsonobjects/NameSpace.java
@@ -0,0 +1,47 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.datastore.jsonobjects;
+
+import java.util.List;
+
+
+public class NameSpace {
+ private String name;
+ private List<String> admin;
+
+ public List<String> getAdmin() {
+ return admin;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setAdmin(List<String> admin) {
+ this.admin = admin;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+}
diff --git a/src/main/java/org/onap/music/eelf/logging/EELFLoggerDelegate.java b/src/main/java/org/onap/music/eelf/logging/EELFLoggerDelegate.java
new file mode 100644
index 00000000..27ae4712
--- /dev/null
+++ b/src/main/java/org/onap/music/eelf/logging/EELFLoggerDelegate.java
@@ -0,0 +1,354 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.eelf.logging;
+
+import static com.att.eelf.configuration.Configuration.MDC_SERVER_FQDN;
+import static com.att.eelf.configuration.Configuration.MDC_SERVER_IP_ADDRESS;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_INSTANCE_ID;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
+import java.net.InetAddress;
+import java.text.MessageFormat;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.servlet.http.HttpServletRequest;
+import org.slf4j.MDC;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.att.eelf.configuration.SLF4jWrapper;
+
+public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
+
+ public static final EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+ public static final EELFLogger applicationLogger =
+ EELFManager.getInstance().getApplicationLogger();
+ public static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+ public static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
+ public static final EELFLogger debugLogger = EELFManager.getInstance().getDebugLogger();
+
+ private String className;
+ private static ConcurrentMap<String, EELFLoggerDelegate> classMap = new ConcurrentHashMap<>();
+
+ public EELFLoggerDelegate(final String className) {
+ super(className);
+ this.className = className;
+ }
+
+ /**
+ * Convenience method that gets a logger for the specified class.
+ *
+ * @see #getLogger(String)
+ *
+ * @param clazz
+ * @return Instance of EELFLoggerDelegate
+ */
+ public static EELFLoggerDelegate getLogger(Class<?> clazz) {
+ return getLogger(clazz.getName());
+ }
+
+ /**
+ * Gets a logger for the specified class name. If the logger does not already exist in the map,
+ * this creates a new logger.
+ *
+ * @param className If null or empty, uses EELFLoggerDelegate as the class name.
+ * @return Instance of EELFLoggerDelegate
+ */
+ public static EELFLoggerDelegate getLogger(final String className) {
+ String classNameNeverNull = className == null || "".equals(className)
+ ? EELFLoggerDelegate.class.getName()
+ : className;
+ EELFLoggerDelegate delegate = classMap.get(classNameNeverNull);
+ if (delegate == null) {
+ delegate = new EELFLoggerDelegate(className);
+ classMap.put(className, delegate);
+ }
+ return delegate;
+ }
+
+ /**
+ * Logs a message at the lowest level: trace.
+ *
+ * @param logger
+ * @param msg
+ */
+ public void trace(EELFLogger logger, String msg) {
+ if (logger.isTraceEnabled()) {
+ logger.trace(msg);
+ }
+ }
+
+ /**
+ * Logs a message with parameters at the lowest level: trace.
+ *
+ * @param logger
+ * @param msg
+ * @param arguments
+ */
+ public void trace(EELFLogger logger, String msg, Object... arguments) {
+ if (logger.isTraceEnabled()) {
+ logger.trace(msg, arguments);
+ }
+ }
+
+ /**
+ * Logs a message and throwable at the lowest level: trace.
+ *
+ * @param logger
+ * @param msg
+ * @param th
+ */
+ public void trace(EELFLogger logger, String msg, Throwable th) {
+ if (logger.isTraceEnabled()) {
+ logger.trace(msg, th);
+ }
+ }
+
+ /**
+ * Logs a message at the second-lowest level: debug.
+ *
+ * @param logger
+ * @param msg
+ */
+ public void debug(EELFLogger logger, String msg) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(msg);
+ }
+ }
+
+ /**
+ * Logs a message with parameters at the second-lowest level: debug.
+ *
+ * @param logger
+ * @param msg
+ * @param arguments
+ */
+ public void debug(EELFLogger logger, String msg, Object... arguments) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(msg, arguments);
+ }
+ }
+
+ /**
+ * Logs a message and throwable at the second-lowest level: debug.
+ *
+ * @param logger
+ * @param msg
+ * @param th
+ */
+ public void debug(EELFLogger logger, String msg, Throwable th) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(msg, th);
+ }
+ }
+
+ /**
+ * Logs a message at info level.
+ *
+ * @param logger
+ * @param msg
+ */
+ public void info(EELFLogger logger, String msg) {
+ logger.info(msg);
+ }
+
+ /**
+ * Logs a message with parameters at info level.
+ *
+ * @param logger
+ * @param msg
+ * @param arguments
+ */
+ public void info(EELFLogger logger, String msg, Object... arguments) {
+ logger.info(msg, arguments);
+ }
+
+ /**
+ * Logs a message and throwable at info level.
+ *
+ * @param logger
+ * @param msg
+ * @param th
+ */
+ public void info(EELFLogger logger, String msg, Throwable th) {
+ logger.info(msg, th);
+ }
+
+ /**
+ * Logs a message at warn level.
+ *
+ * @param logger
+ * @param msg
+ */
+ public void warn(EELFLogger logger, String msg) {
+ logger.warn(msg);
+ }
+
+ /**
+ * Logs a message with parameters at warn level.
+ *
+ * @param logger
+ * @param msg
+ * @param arguments
+ */
+ public void warn(EELFLogger logger, String msg, Object... arguments) {
+ logger.warn(msg, arguments);
+ }
+
+ /**
+ * Logs a message and throwable at warn level.
+ *
+ * @param logger
+ * @param msg
+ * @param th
+ */
+ public void warn(EELFLogger logger, String msg, Throwable th) {
+ logger.warn(msg, th);
+ }
+
+ /**
+ * Logs a message at error level.
+ *
+ * @param logger
+ * @param msg
+ */
+ public void error(EELFLogger logger, String msg) {
+ logger.error(msg);
+ }
+
+ /**
+ * Logs a message with parameters at error level.
+ *
+ * @param logger
+ * @param msg
+ * @param arguments
+ */
+ public void error(EELFLogger logger, String msg, Object... arguments) {
+ logger.warn(msg, arguments);
+ }
+
+ /**
+ * Logs a message and throwable at error level.
+ *
+ * @param logger
+ * @param msg
+ * @param th
+ */
+ public void error(EELFLogger logger, String msg, Throwable th) {
+ logger.warn(msg, th);
+ }
+
+ /**
+ * Logs a message with the associated alarm severity at error level.
+ *
+ * @param logger
+ * @param msg
+ * @param severtiy
+ */
+ public void error(EELFLogger logger, String msg, Object /* AlarmSeverityEnum */ severtiy) {
+ logger.error(msg);
+ }
+
+ /**
+ * Initializes the logger context.
+ */
+ public void init() {
+ setGlobalLoggingContext();
+ final String msg =
+ "############################ Logging is started. ############################";
+ // These loggers emit the current date-time without being told.
+ info(applicationLogger, msg);
+ error(errorLogger, msg);
+ debug(debugLogger, msg);
+ info(auditLogger, msg);
+ info(metricsLogger, msg);
+ }
+
+ /**
+ * Builds a message using a template string and the arguments.
+ *
+ * @param message
+ * @param args
+ * @return
+ */
+ private String formatMessage(String message, Object... args) {
+ StringBuilder sbFormattedMessage = new StringBuilder();
+ if (args != null && args.length > 0 && message != null && message != "") {
+ MessageFormat mf = new MessageFormat(message);
+ sbFormattedMessage.append(mf.format(args));
+ } else {
+ sbFormattedMessage.append(message);
+ }
+
+ return sbFormattedMessage.toString();
+ }
+
+ /**
+ * Loads all the default logging fields into the MDC context.
+ */
+ private void setGlobalLoggingContext() {
+ MDC.put(MDC_SERVICE_INSTANCE_ID, "");
+ try {
+ MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getHostName());
+ MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
+ } catch (Exception e) {
+ errorLogger.error("setGlobalLoggingContext failed", e);
+ }
+ }
+
+ public static void mdcPut(String key, String value) {
+ MDC.put(key, value);
+ }
+
+ public static String mdcGet(String key) {
+ return MDC.get(key);
+ }
+
+ public static void mdcRemove(String key) {
+ MDC.remove(key);
+ }
+
+ /**
+ * Loads the RequestId/TransactionId into the MDC which it should be receiving with an each
+ * incoming REST API request. Also, configures few other request based logging fields into the
+ * MDC context.
+ *
+ * @param req
+ * @param appName
+ */
+ public void setRequestBasedDefaultsIntoGlobalLoggingContext(HttpServletRequest req,
+ String appName) {
+ // Load the default fields
+ setGlobalLoggingContext();
+
+ // Load the request based fields
+ if (req != null) {
+ // Rest Path
+ MDC.put(MDC_SERVICE_NAME, req.getServletPath());
+
+ // Client IPAddress i.e. IPAddress of the remote host who is making
+ // this request.
+ String clientIPAddress = req.getHeader("X-FORWARDED-FOR");
+ if (clientIPAddress == null) {
+ clientIPAddress = req.getRemoteAddr();
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/onap/music/exceptions/MusicLockingException.java b/src/main/java/org/onap/music/exceptions/MusicLockingException.java
new file mode 100644
index 00000000..1a9e45d9
--- /dev/null
+++ b/src/main/java/org/onap/music/exceptions/MusicLockingException.java
@@ -0,0 +1,74 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.exceptions;
+
+/**
+ * @author inam
+ *
+ */
+public class MusicLockingException extends Exception {
+
+ /**
+ *
+ */
+ public MusicLockingException() {
+
+ }
+
+ /**
+ * @param message
+ */
+ public MusicLockingException(String message) {
+ super(message);
+
+ }
+
+ /**
+ * @param cause
+ */
+ public MusicLockingException(Throwable cause) {
+ super(cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public MusicLockingException(String message, Throwable cause) {
+ super(message, cause);
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ * @param enableSuppression
+ * @param writableStackTrace
+ */
+ public MusicLockingException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+
+ }
+
+}
diff --git a/src/main/java/org/onap/music/exceptions/MusicPolicyVoilationException.java b/src/main/java/org/onap/music/exceptions/MusicPolicyVoilationException.java
new file mode 100644
index 00000000..bade21a4
--- /dev/null
+++ b/src/main/java/org/onap/music/exceptions/MusicPolicyVoilationException.java
@@ -0,0 +1,79 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.exceptions;
+
+/**
+ * @author inam
+ *
+ */
+public class MusicPolicyVoilationException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public MusicPolicyVoilationException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ */
+ public MusicPolicyVoilationException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param cause
+ */
+ public MusicPolicyVoilationException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public MusicPolicyVoilationException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ /**
+ * @param message
+ * @param cause
+ * @param enableSuppression
+ * @param writableStackTrace
+ */
+ public MusicPolicyVoilationException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ // TODO Auto-generated constructor stub
+ }
+
+}
diff --git a/src/main/java/org/onap/music/exceptions/MusicQueryException.java b/src/main/java/org/onap/music/exceptions/MusicQueryException.java
new file mode 100644
index 00000000..24b8568b
--- /dev/null
+++ b/src/main/java/org/onap/music/exceptions/MusicQueryException.java
@@ -0,0 +1,89 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.exceptions;
+
+
+
+/**
+ * @author inam
+ *
+ */
+public class MusicQueryException extends Exception {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+ private int errorCode;
+
+
+ /**
+ *
+ */
+ public MusicQueryException() {
+ super();
+ }
+
+ /**
+ * @param message
+ */
+ public MusicQueryException(String message) {
+ super(message);
+ }
+
+
+
+ /**
+ * @param message
+ */
+ public MusicQueryException(String message, int errorCode) {
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+ /**
+ * @param cause
+ */
+ public MusicQueryException(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public MusicQueryException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ * @param enableSuppression
+ * @param writableStackTrace
+ */
+ public MusicQueryException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+}
diff --git a/src/main/java/org/onap/music/exceptions/MusicServiceException.java b/src/main/java/org/onap/music/exceptions/MusicServiceException.java
new file mode 100644
index 00000000..a3b1fc56
--- /dev/null
+++ b/src/main/java/org/onap/music/exceptions/MusicServiceException.java
@@ -0,0 +1,84 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+
+package org.onap.music.exceptions;
+
+/**
+ * @author inam
+ *
+ */
+public class MusicServiceException extends Exception {
+
+
+ private int errorCode;
+ private String errorMessage;
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+
+ public void setErrorCode(int errorCode) {
+ this.errorCode = errorCode;
+ }
+
+
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+
+ public void setErrorMessage(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+
+ public MusicServiceException() {
+ super();
+ }
+
+
+ public MusicServiceException(String message) {
+ super(message);
+
+ }
+
+
+ public MusicServiceException(Throwable cause) {
+ super(cause);
+
+ }
+
+
+ public MusicServiceException(String message, Throwable cause) {
+ super(message, cause);
+
+ }
+
+
+ public MusicServiceException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+
+ }
+
+}
diff --git a/src/main/java/org/onap/music/lockingservice/LockListener.java b/src/main/java/org/onap/music/lockingservice/LockListener.java
new file mode 100644
index 00000000..33188e60
--- /dev/null
+++ b/src/main/java/org/onap/music/lockingservice/LockListener.java
@@ -0,0 +1,39 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.lockingservice;
+
+/**
+ * This class has two methods which are call back methods when a lock is acquired and when the lock
+ * is released.
+ *
+ */
+public interface LockListener {
+ /**
+ * call back called when the lock is acquired
+ */
+ public void lockAcquired();
+
+ /**
+ * call back called when the lock is released.
+ */
+ public void lockReleased();
+}
diff --git a/src/main/java/org/onap/music/lockingservice/MusicLockState.java b/src/main/java/org/onap/music/lockingservice/MusicLockState.java
new file mode 100644
index 00000000..23661ad4
--- /dev/null
+++ b/src/main/java/org/onap/music/lockingservice/MusicLockState.java
@@ -0,0 +1,126 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.lockingservice;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import org.onap.music.main.MusicCore;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+// the state variable that will be stored in zookeeper, capturing the transitions of
+public class MusicLockState implements Serializable {
+ public enum LockStatus {
+ UNLOCKED, BEING_LOCKED, LOCKED
+ };// captures the state of the lock
+
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(MusicLockState.class);
+ LockStatus lockStatus;
+ boolean needToSyncQuorum = false;
+ String lockHolder;
+ long leasePeriod = Long.MAX_VALUE, leaseStartTime = -1;
+
+ public MusicLockState(LockStatus lockStatus, String lockHolder) {
+ this.lockStatus = lockStatus;
+ this.lockHolder = lockHolder;
+ }
+
+ public MusicLockState(LockStatus lockStatus, String lockHolder, boolean needToSyncQuorum) {
+ this.lockStatus = lockStatus;
+ this.lockHolder = lockHolder;
+ this.needToSyncQuorum = needToSyncQuorum;
+ }
+
+
+ public long getLeasePeriod() {
+ return leasePeriod;
+ }
+
+ public boolean isNeedToSyncQuorum() {
+ return needToSyncQuorum;
+ }
+
+
+
+ public void setLeasePeriod(long leasePeriod) {
+ this.leasePeriod = leasePeriod;
+ }
+
+
+ public long getLeaseStartTime() {
+ return leaseStartTime;
+ }
+
+
+ public void setLeaseStartTime(long leaseStartTime) {
+ this.leaseStartTime = leaseStartTime;
+ }
+
+
+
+ public LockStatus getLockStatus() {
+ return lockStatus;
+ }
+
+ public void setLockStatus(LockStatus lockStatus) {
+ this.lockStatus = lockStatus;
+ }
+
+ public String getLockHolder() {
+ return lockHolder;
+ }
+
+ public void setLockHolder(String lockHolder) {
+ this.lockHolder = lockHolder;
+ }
+
+ public byte[] serialize() {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutput out = null;
+ try {
+ out = new ObjectOutputStream(bos);
+ out.writeObject(this);
+ } catch (IOException e) {
+ logger.error(e.getMessage());
+ }
+ return bos.toByteArray();
+ }
+
+ public static MusicLockState deSerialize(byte[] data) {
+ ByteArrayInputStream bis = new ByteArrayInputStream(data);
+ Object o = null;
+ ObjectInput in = null;
+ try {
+ in = new ObjectInputStream(bis);
+ o = in.readObject();
+ } catch (ClassNotFoundException | IOException e) {
+ logger.error(e.getMessage());
+ }
+ return (MusicLockState) o;
+ }
+}
diff --git a/src/main/java/org/onap/music/lockingservice/MusicLockingService.java b/src/main/java/org/onap/music/lockingservice/MusicLockingService.java
new file mode 100644
index 00000000..59b502ca
--- /dev/null
+++ b/src/main/java/org/onap/music/lockingservice/MusicLockingService.java
@@ -0,0 +1,142 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.lockingservice;
+
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+import java.util.concurrent.CountDownLatch;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.onap.music.exceptions.MusicServiceException;
+import org.onap.music.main.MusicCore;
+import org.onap.music.main.MusicUtil;
+import org.apache.zookeeper.ZooKeeper;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.music.datastore.MusicDataStore;
+import org.onap.music.eelf.logging.EELFLoggerDelegate;
+
+public class MusicLockingService implements Watcher {
+
+ private static final int SESSION_TIMEOUT = 180000;
+ ZkStatelessLockService zkLockHandle = null;
+ private CountDownLatch connectedSignal = new CountDownLatch(1);
+ private static EELFLogger logger =
+ EELFManager.getInstance().getLogger(MusicLockingService.class);
+ // private static EELFLoggerDelegate logger =
+ // EELFLoggerDelegate.getLogger(MusicLockingService.class);
+
+ public MusicLockingService() throws MusicServiceException {
+ try {
+ ZooKeeper zk = new ZooKeeper(MusicUtil.getMyZkHost(), SESSION_TIMEOUT, this);
+ connectedSignal.await();
+ zkLockHandle = new ZkStatelessLockService(zk);
+ } catch (IOException e) {
+ logger.error(e.getMessage());
+ throw new MusicServiceException("IO Error has occured" + e.getMessage());
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ throw new MusicServiceException("Exception Occured " + e.getMessage());
+ }
+ }
+
+ public ZkStatelessLockService getzkLockHandle() {
+ return zkLockHandle;
+ }
+
+ public MusicLockingService(String lockServer) {
+ try {
+ ZooKeeper zk = new ZooKeeper(lockServer, SESSION_TIMEOUT, this);
+ connectedSignal.await();
+ zkLockHandle = new ZkStatelessLockService(zk);
+ } catch (IOException | InterruptedException e) {
+ logger.error(e.getMessage());
+ }
+ }
+
+ public void createLockaIfItDoesNotExist(String lockName) {
+ if (zkLockHandle.checkIfLockExists(lockName) == false) {
+ String lockHolder = null;
+ MusicLockState ml = new MusicLockState(MusicLockState.LockStatus.UNLOCKED, lockHolder);
+ byte[] data = ml.serialize();
+ zkLockHandle.createLock(lockName, data);
+ }
+ }
+
+ public void setLockState(String lockName, MusicLockState mls) {
+ byte[] data = mls.serialize();
+ zkLockHandle.setNodeData(lockName, data);
+ }
+
+ public MusicLockState getLockState(String lockName) {
+
+ byte[] data = zkLockHandle.getNodeData(lockName);
+ return MusicLockState.deSerialize(data);
+ }
+
+ public String createLockId(String lockName) {
+ String lockIdWithSlash = zkLockHandle.createLockId(lockName);
+ return lockIdWithSlash.replace('/', '$');
+ }
+
+ public boolean isMyTurn(String lockIdWithDollar) {
+ String lockId = lockIdWithDollar.replace('$', '/');
+ StringTokenizer st = new StringTokenizer(lockId);
+ String lockName = "/" + st.nextToken("/");
+ try {
+ return zkLockHandle.lock(lockName, lockId);
+ } catch (KeeperException | InterruptedException e) {
+ logger.error(e.getMessage());
+ }
+ return false;
+ }
+
+ public void unlockAndDeleteId(String lockIdWithDollar) {
+ String lockId = lockIdWithDollar.replace('$', '/');
+ zkLockHandle.unlock(lockId);
+ }
+
+ public void deleteLock(String lockName) {
+ zkLockHandle.deleteLock(lockName);
+ }
+
+ public String whoseTurnIsIt(String lockName) {
+ String lockHolder = zkLockHandle.currentLockHolder(lockName);
+ return lockHolder.replace('/', '$');
+
+ }
+
+ public void process(WatchedEvent event) { // Watcher interface
+ if (event.getState() == KeeperState.SyncConnected) {
+ connectedSignal.countDown();
+ }
+ }
+
+
+ public void close() {
+ zkLockHandle.close();
+ }
+
+}
diff --git a/src/main/java/org/onap/music/lockingservice/ProtocolSupport.java b/src/main/java/org/onap/music/lockingservice/ProtocolSupport.java
new file mode 100644
index 00000000..37ae9e96
--- /dev/null
+++ b/src/main/java/org/onap/music/lockingservice/ProtocolSupport.java
@@ -0,0 +1,205 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.lockingservice;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+import org.onap.music.lockingservice.ZooKeeperOperation;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A base class for protocol implementations which provides a number of higher level helper methods
+ * for working with ZooKeeper along with retrying synchronous operations if the connection to
+ * ZooKeeper closes such as {@link #retryOperation(ZooKeeperOperation)}
+ *
+ */
+class ProtocolSupport {
+ private static final Logger LOG = LoggerFactory.getLogger(ProtocolSupport.class);
+
+ protected ZooKeeper zookeeper;
+ private AtomicBoolean closed = new AtomicBoolean(false);
+ private long retryDelay = 500L;
+ private int retryCount = 10;
+ private List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;
+
+ // public ProtocolSupport(ZooKeeper zookeeper) {
+ // this.zookeeper = zookeeper;
+ // }
+
+ /**
+ * Closes this strategy and releases any ZooKeeper resources; but keeps the ZooKeeper instance
+ * open
+ */
+ public void close() {
+ if (closed.compareAndSet(false, true)) {
+ doClose();
+ }
+ }
+
+ /**
+ * return zookeeper client instance
+ *
+ * @return zookeeper client instance
+ */
+ public ZooKeeper getZookeeper() {
+ return zookeeper;
+ }
+
+ /**
+ * return the acl its using
+ *
+ * @return the acl.
+ */
+ public List<ACL> getAcl() {
+ return acl;
+ }
+
+ /**
+ * set the acl
+ *
+ * @param acl the acl to set to
+ */
+ public void setAcl(List<ACL> acl) {
+ this.acl = acl;
+ }
+
+ /**
+ * get the retry delay in milliseconds
+ *
+ * @return the retry delay
+ */
+ public long getRetryDelay() {
+ return retryDelay;
+ }
+
+ /**
+ * Sets the time waited between retry delays
+ *
+ * @param retryDelay the retry delay
+ */
+ public void setRetryDelay(long retryDelay) {
+ this.retryDelay = retryDelay;
+ }
+
+ /**
+ * Allow derived classes to perform some custom closing operations to release resources
+ */
+ protected void doClose() {}
+
+
+ /**
+ * Perform the given operation, retrying if the connection fails
+ *
+ * @return object. it needs to be cast to the callee's expected return type.
+ * @param operation FILL IN
+ * @throws KeeperException FILL IN
+ * @throws InterruptedException FILL IN
+ */
+ protected Object retryOperation(ZooKeeperOperation operation)
+ throws KeeperException, InterruptedException {
+ KeeperException exception = null;
+ for (int i = 0; i < retryCount; i++) {
+ try {
+ return operation.execute();
+ } catch (KeeperException.SessionExpiredException e) {
+ LOG.warn("Session expired for: " + zookeeper + " so reconnecting due to: " + e, e);
+ throw e;
+ } catch (KeeperException.ConnectionLossException e) {
+ if (exception == null) {
+ exception = e;
+ }
+ LOG.debug("Attempt " + i + " failed with connection loss so "
+ + "attempting to reconnect: " + e, e);
+ retryDelay(i);
+ }
+ }
+ throw exception;
+ }
+
+ /**
+ * Ensures that the given path exists with no data, the current ACL and no flags
+ *
+ * @param path the lock path
+ */
+ protected void ensurePathExists(String path) {
+ ensureExists(path, null, acl, CreateMode.PERSISTENT);
+ }
+
+ /**
+ * Ensures that the given path exists with the given data, ACL and flags
+ *
+ * @param path the lock path
+ * @param data the data
+ * @param acl list of ACLs applying to the path
+ * @param flags create mode flags
+ */
+ protected void ensureExists(final String path, final byte[] data, final List<ACL> acl,
+ final CreateMode flags) {
+ try {
+ retryOperation(new ZooKeeperOperation() {
+ public boolean execute() throws KeeperException, InterruptedException {
+ Stat stat = zookeeper.exists(path, false);
+ if (stat != null) {
+ return true;
+ }
+ zookeeper.create(path, data, acl, flags);
+ return true;
+ }
+ });
+ } catch (KeeperException e) {
+ LOG.warn("Caught: " + e, e);
+ } catch (InterruptedException e) {
+ LOG.warn("Caught: " + e, e);
+ }
+ }
+
+ /**
+ * Returns true if this protocol has been closed
+ *
+ * @return true if this protocol is closed
+ */
+ protected boolean isClosed() {
+ return closed.get();
+ }
+
+ /**
+ * Performs a retry delay if this is not the first attempt
+ *
+ * @param attemptCount the number of the attempts performed so far
+ */
+ protected void retryDelay(int attemptCount) {
+ if (attemptCount > 0) {
+ try {
+ Thread.sleep(attemptCount * retryDelay);
+ } catch (InterruptedException e) {
+ LOG.debug("Failed to sleep: " + e, e);
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/onap/music/lockingservice/ZNodeName.java b/src/main/java/org/onap/music/lockingservice/ZNodeName.java
new file mode 100644
index 00000000..c8d14cba
--- /dev/null
+++ b/src/main/java/org/onap/music/lockingservice/ZNodeName.java
@@ -0,0 +1,117 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.lockingservice;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * Represents an ephemeral znode name which has an ordered sequence number and can be sorted in
+ * order
+ *
+ */
+class ZNodeName implements Comparable<ZNodeName> {
+ private final String name;
+ private String prefix;
+ private int sequence = -1;
+ private static EELFLogger LOG = EELFManager.getInstance().getLogger(ZNodeName.class);
+
+ public ZNodeName(String name) {
+ if (name == null) {
+ throw new NullPointerException("id cannot be null");
+ }
+ this.name = name;
+ this.prefix = name;
+ int idx = name.lastIndexOf('-');
+ if (idx >= 0) {
+ this.prefix = name.substring(0, idx);
+ try {
+ this.sequence = Integer.parseInt(name.substring(idx + 1));
+ // If an exception occurred we misdetected a sequence suffix,
+ // so return -1.
+ } catch (NumberFormatException e) {
+ LOG.info("Number format exception for " + idx, e);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ LOG.info("Array out of bounds for " + idx, e);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return name.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+
+ ZNodeName sequence = (ZNodeName) o;
+
+ if (!name.equals(sequence.name))
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode() + 37;
+ }
+
+ public int compareTo(ZNodeName that) {
+ int answer = this.prefix.compareTo(that.prefix);
+ if (answer == 0) {
+ int s1 = this.sequence;
+ int s2 = that.sequence;
+ if (s1 == -1 && s2 == -1) {
+ return this.name.compareTo(that.name);
+ }
+ answer = s1 == -1 ? 1 : s2 == -1 ? -1 : s1 - s2;
+ }
+ return answer;
+ }
+
+ /**
+ * Returns the name of the znode
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the sequence number
+ */
+ public int getZNodeName() {
+ return sequence;
+ }
+
+ /**
+ * Returns the text prefix before the sequence number
+ */
+ public String getPrefix() {
+ return prefix;
+ }
+}
diff --git a/src/main/java/org/onap/music/lockingservice/ZkStatelessLockService.java b/src/main/java/org/onap/music/lockingservice/ZkStatelessLockService.java
new file mode 100644
index 00000000..99ccd4db
--- /dev/null
+++ b/src/main/java/org/onap/music/lockingservice/ZkStatelessLockService.java
@@ -0,0 +1,334 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.lockingservice;
+
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+/**
+ * A <a href="package.html">protocol to implement an exclusive write lock or to elect a leader</a>.
+ * <p/>
+ * You invoke {@link #lock()} to start the process of grabbing the lock; you may get the lock then
+ * or it may be some time later.
+ * <p/>
+ * You can register a listener so that you are invoked when you get the lock; otherwise you can ask
+ * if you have the lock by calling {@link #isOwner()}
+ *
+ */
+public class ZkStatelessLockService extends ProtocolSupport {
+ public ZkStatelessLockService(ZooKeeper zk) {
+ zookeeper = zk;
+ }
+
+ private static EELFLogger LOG =
+ EELFManager.getInstance().getLogger(ZkStatelessLockService.class);
+
+ protected void createLock(final String path, final byte[] data) {
+ final List<ACL> acl = ZooDefs.Ids.OPEN_ACL_UNSAFE;
+ try {
+ retryOperation(new ZooKeeperOperation() {
+ public boolean execute() throws KeeperException, InterruptedException {
+ zookeeper.create(path, data, acl, CreateMode.PERSISTENT);
+ return true;
+ }
+ });
+ } catch (KeeperException e) {
+ LOG.info("Caught: " + e, e);
+ } catch (InterruptedException e) {
+ LOG.info("Caught: " + e, e);
+ }
+ }
+
+ public void close() {
+ try {
+ zookeeper.close();
+ } catch (InterruptedException e) {
+ LOG.info(e.getMessage());
+ }
+ }
+
+ public void setNodeData(final String lockName, final byte[] data) {
+ try {
+ retryOperation(new ZooKeeperOperation() {
+ public boolean execute() throws KeeperException, InterruptedException {
+ zookeeper.getSessionId();
+ zookeeper.setData("/" + lockName, data, -1);
+ return true;
+ }
+ });
+ } catch (KeeperException e) {
+ LOG.info("Caught: " + e, e);
+ } catch (InterruptedException e) {
+ LOG.info("Caught: " + e, e);
+ }
+
+ }
+
+ public byte[] getNodeData(final String lockName) {
+ try {
+ if (zookeeper.exists("/" + lockName, null) != null)
+ return zookeeper.getData("/" + lockName, false, null);
+ else
+ return null;
+
+ } catch (KeeperException e) {
+ LOG.info("Caught: " + e, e);
+ } catch (InterruptedException e) {
+ LOG.info("Caught: " + e, e);
+ }
+ return null;
+ }
+
+ public boolean checkIfLockExists(String lockName) {
+ boolean result = false;
+ try {
+ Stat stat = zookeeper.exists(lockName, false);
+ if (stat != null) {
+ result = true;
+ }
+ } catch (KeeperException e) {
+ LOG.info(e.getMessage());
+ } catch (InterruptedException e) {
+ LOG.info(e.getMessage());
+ }
+ return result;
+ }
+
+ public void createNode(String nodeName) {
+ ensurePathExists(nodeName);
+ }
+
+ public String createLockId(String dir) {
+ ensurePathExists(dir);
+ LockZooKeeperOperation zop = new LockZooKeeperOperation(dir);
+
+ try {
+ retryOperation(zop);
+ } catch (KeeperException e) {
+ LOG.info(e.getMessage());
+ } catch (InterruptedException e) {
+ LOG.info(e.getMessage());
+ }
+ return zop.getId();
+ }
+
+ /**
+ * Attempts to acquire the exclusive write lock returning whether or not it was acquired. Note
+ * that the exclusive lock may be acquired some time later after this method has been invoked
+ * due to the current lock owner going away.
+ */
+ public synchronized boolean lock(String dir, String lockId)
+ throws KeeperException, InterruptedException {
+ if (isClosed()) {
+ return false;
+ }
+ LockZooKeeperOperation zop = new LockZooKeeperOperation(dir, lockId);
+ return (Boolean) retryOperation(zop);
+ }
+
+ /**
+ * Removes the lock or associated znode if you no longer require the lock. this also removes
+ * your request in the queue for locking in case you do not already hold the lock.
+ *
+ * @throws RuntimeException throws a runtime exception if it cannot connect to zookeeper.
+ */
+ public synchronized void unlock(String lockId) throws RuntimeException {
+ final String id = lockId;
+ if (!isClosed() && id != null) {
+ try {
+ ZooKeeperOperation zopdel = new ZooKeeperOperation() {
+ public boolean execute() throws KeeperException, InterruptedException {
+ zookeeper.delete(id, -1);
+ return Boolean.TRUE;
+ }
+ };
+ zopdel.execute();
+ } catch (InterruptedException e) {
+ LOG.info("Caught: " + e, e);
+ // set that we have been interrupted.
+ Thread.currentThread().interrupt();
+ } catch (KeeperException.NoNodeException e) {
+ // do nothing
+ } catch (KeeperException e) {
+ LOG.info("Caught: " + e, e);
+ throw (RuntimeException) new RuntimeException(e.getMessage()).initCause(e);
+ }
+ }
+ }
+
+ public synchronized String currentLockHolder(String mainLock) {
+ final String id = mainLock;
+ if (!isClosed() && id != null) {
+ List<String> names;
+ try {
+ names = zookeeper.getChildren(id, false);
+ if (names.isEmpty())
+ return "";
+ SortedSet<ZNodeName> sortedNames = new TreeSet<ZNodeName>();
+ for (String name : names) {
+ sortedNames.add(new ZNodeName(id + "/" + name));
+ }
+ return sortedNames.first().getName();
+ } catch (InterruptedException e) {
+ LOG.info("Caught: " + e, e);
+ // set that we have been interrupted.
+ Thread.currentThread().interrupt();
+ } catch (KeeperException.NoNodeException e) {
+ // do nothing
+ } catch (KeeperException e) {
+ LOG.info("Caught: " + e, e);
+ throw (RuntimeException) new RuntimeException(e.getMessage()).initCause(e);
+ }
+ }
+ return "No lock holder!";
+ }
+
+ public synchronized void deleteLock(String mainLock) {
+ final String id = mainLock;
+ if (!isClosed() && id != null) {
+ try {
+ ZooKeeperOperation zopdel = new ZooKeeperOperation() {
+ public boolean execute() throws KeeperException, InterruptedException {
+ List<String> names = zookeeper.getChildren(id, false);
+ for (String name : names) {
+ zookeeper.delete(id + "/" + name, -1);
+ }
+ zookeeper.delete(id, -1);
+ return Boolean.TRUE;
+ }
+ };
+ zopdel.execute();
+ } catch (InterruptedException e) {
+ LOG.info("Caught: " + e, e);
+ // set that we have been interrupted.
+ Thread.currentThread().interrupt();
+ } catch (KeeperException.NoNodeException e) {
+ // do nothing
+ } catch (KeeperException e) {
+ LOG.info("Caught: " + e, e);
+ throw (RuntimeException) new RuntimeException(e.getMessage()).initCause(e);
+ }
+ }
+
+ }
+
+ /**
+ * a zoookeeper operation that is mainly responsible for all the magic required for locking.
+ */
+ private class LockZooKeeperOperation implements ZooKeeperOperation {
+
+ /**
+ * find if we have been created earlier if not create our node
+ *
+ * @param prefix the prefix node
+ * @param zookeeper the zookeeper client
+ * @param dir the dir parent
+ * @throws KeeperException
+ * @throws InterruptedException
+ */
+ private String dir;
+ private String id = null;
+
+ public String getId() {
+ return id;
+ }
+
+ public LockZooKeeperOperation(String dir) {
+ this.dir = dir;
+ }
+
+ public LockZooKeeperOperation(String dir, String id) {
+ this.dir = dir;
+ this.id = id;
+ }
+
+ /**
+ * the command that is run and retried for actually obtaining the lock
+ *
+ * @return if the command was successful or not
+ */
+ public boolean execute() throws KeeperException, InterruptedException {
+ do {
+ if (id == null) {
+ String prefix = "x-";
+ byte[] data = {0x12, 0x34};
+ id = zookeeper.create(dir + "/" + prefix, data, getAcl(),
+ CreateMode.PERSISTENT_SEQUENTIAL);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Created id: " + id);
+ }
+ if (id != null)
+ break;
+ }
+ if (id != null) {
+ List<String> names = zookeeper.getChildren(dir, false);
+ if (names.isEmpty()) {
+ LOG.info("No children in: " + dir + " when we've just "
+ + "created one! Lets recreate it...");
+ // lets force the recreation of the id
+ id = null;
+ } else {
+ // lets sort them explicitly (though they do seem to come back in order
+ // ususally :)
+ ZNodeName idName = new ZNodeName(id);
+ SortedSet<ZNodeName> sortedNames = new TreeSet<ZNodeName>();
+ for (String name : names) {
+ sortedNames.add(new ZNodeName(dir + "/" + name));
+ }
+ if (!sortedNames.contains(idName))
+ return Boolean.FALSE;
+
+ SortedSet<ZNodeName> lessThanMe = sortedNames.headSet(idName);
+ if (!lessThanMe.isEmpty()) {
+ ZNodeName lastChildName = lessThanMe.last();
+ String lastChildId = lastChildName.getName();
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("watching less than me node: " + lastChildId);
+ }
+ Stat stat = zookeeper.exists(lastChildId, false);
+ if (stat != null) {
+ return Boolean.FALSE;
+ } else {
+ LOG.info("Could not find the" + " stats for less than me: "
+ + lastChildName.getName());
+ }
+ } else
+ return Boolean.TRUE;
+ }
+ }
+ } while (id == null);
+ return Boolean.FALSE;
+ }
+ }
+
+}
+
diff --git a/src/main/java/org/onap/music/lockingservice/ZooKeeperOperation.java b/src/main/java/org/onap/music/lockingservice/ZooKeeperOperation.java
new file mode 100644
index 00000000..7020d14d
--- /dev/null
+++ b/src/main/java/org/onap/music/lockingservice/ZooKeeperOperation.java
@@ -0,0 +1,42 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.lockingservice;
+
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * A callback object which can be used for implementing retry-able operations in the
+ * {@link org.onap.music.lockingservice.ProtocolSupport} class
+ *
+ */
+public interface ZooKeeperOperation {
+
+ /**
+ * Performs the operation - which may be involved multiple times if the connection
+ * to ZooKeeper closes during this operation
+ *
+ * @return the result of the operation or null
+ * @throws KeeperException FILL IN
+ * @throws InterruptedException FILL IN
+ */
+ public boolean execute() throws KeeperException, InterruptedException;
+}
diff --git a/src/main/java/org/onap/music/main/CachingUtil.java b/src/main/java/org/onap/music/main/CachingUtil.java
new file mode 100755
index 00000000..0ab055df
--- /dev/null
+++ b/src/main/java/org/onap/music/main/CachingUtil.java
@@ -0,0 +1,370 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.main;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.jcs.JCS;
+import org.apache.commons.jcs.access.CacheAccess;
+import org.apache.log4j.Logger;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.onap.music.datastore.jsonobjects.AAFResponse;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.music.datastore.PreparedQueryObject;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+
+/**
+ * All Caching related logic is handled by this class and a schedule cron runs to update cache.
+ *
+ * @author Vikram
+ *
+ */
+public class CachingUtil implements Runnable {
+
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(CachingUtil.class);
+
+ private static CacheAccess<String, String> musicCache = JCS.getInstance("musicCache");
+ private static CacheAccess<String, Map<String, String>> aafCache = JCS.getInstance("aafCache");
+ private static CacheAccess<String, String> appNameCache = JCS.getInstance("appNameCache");
+ private static Map<String, Number> userAttempts = new HashMap<>();
+ private static Map<String, Calendar> lastFailedTime = new HashMap<>();
+
+ public boolean isCacheRefreshNeeded() {
+ if (aafCache.get("initBlankMap") == null)
+ return true;
+ return false;
+ }
+
+ public void initializeMusicCache() {
+ logger.info("Initializing Music Cache...");
+ musicCache.put("isInitialized", "true");
+ }
+
+ public void initializeAafCache() {
+ logger.info("Resetting and initializing AAF Cache...");
+
+ // aafCache.clear();
+ // loop through aafCache ns .. only the authenticated ns will be re cached. and non
+ // authenticated will wait for user to retry.
+ String query = "SELECT application_name, keyspace_name, username, password FROM admin.keyspace_master WHERE is_api = ? allow filtering";
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(query);
+ try {
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), false));
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ logger.error("Exception is " + e1.getMessage() + "during initalizeAafCache");
+ }
+ ResultSet rs = MusicCore.get(pQuery);
+ Iterator<Row> it = rs.iterator();
+ Map<String, String> map = null;
+ while (it.hasNext()) {
+ Row row = it.next();
+ String nameSpace = row.getString("keyspace_name");
+ String userId = row.getString("username");
+ String password = row.getString("password");
+ String keySpace = row.getString("application_name");
+ try {
+ userAttempts.put(nameSpace, 0);
+ AAFResponse responseObj = triggerAAF(nameSpace, userId, password);
+ if (responseObj.getNs().size() > 0) {
+ map = new HashMap<>();
+ map.put(userId, password);
+ aafCache.put(nameSpace, map);
+ musicCache.put(nameSpace, keySpace);
+ logger.debug("Cronjob: Cache Updated with AAF response for namespace "
+ + nameSpace);
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ logger.error("Something at AAF was changed for ns: " + nameSpace
+ + ". So not updating Cache for the namespace. ");
+ logger.error("Exception is " + e.getMessage());
+ }
+ }
+
+ }
+
+ @Override
+ public void run() {
+ logger.debug("Scheduled task invoked. Refreshing Cache...");
+ initializeAafCache();
+ }
+
+ public static boolean authenticateAAFUser(String nameSpace, String userId, String password,
+ String keySpace) throws Exception {
+
+ if (aafCache.get(nameSpace) != null) {
+ if (!musicCache.get(nameSpace).equals(keySpace)) {
+ logger.debug("Create new application for the same namespace.");
+ } else if (aafCache.get(nameSpace).get(userId).equals(password)) {
+ logger.debug("Authenticated with cache value..");
+ // reset invalid attempts to 0
+ userAttempts.put(nameSpace, 0);
+ return true;
+ } else {
+ // call AAF update cache with new password
+ if (userAttempts.get(nameSpace) == null)
+ userAttempts.put(nameSpace, 0);
+ if ((Integer) userAttempts.get(nameSpace) >= 3) {
+ logger.info("Reached max attempts. Checking if time out..");
+ logger.info("Failed time: " + lastFailedTime.get(nameSpace).getTime());
+ Calendar calendar = Calendar.getInstance();
+ long delayTime = (calendar.getTimeInMillis()
+ - lastFailedTime.get(nameSpace).getTimeInMillis());
+ logger.info("Delayed time: " + delayTime);
+ if (delayTime > 120000) {
+ logger.info("Resetting failed attempt.");
+ userAttempts.put(nameSpace, 0);
+ } else {
+ throw new Exception(
+ "No more attempts allowed. Please wait for atleast 2 min.");
+ }
+ }
+ logger.error("Cache not authenticated..");
+ logger.info("Check AAF again...");
+ }
+ }
+
+ AAFResponse responseObj = triggerAAF(nameSpace, userId, password);
+ if (responseObj.getNs().size() > 0) {
+ if (responseObj.getNs().get(0).getAdmin().contains(userId))
+ return true;
+
+ }
+ logger.info("Invalid user. Cache not updated");
+ return false;
+ }
+
+ private static AAFResponse triggerAAF(String nameSpace, String userId, String password)
+ throws Exception {
+ if (MusicUtil.getAafEndpointUrl() == null) {
+ throw new Exception("AAF endpoint is not set. Please specify in the properties file.");
+ }
+ Client client = Client.create();
+ // WebResource webResource =
+ // client.resource("https://aaftest.test.att.com:8095/proxy/authz/nss/"+nameSpace);
+ WebResource webResource = client.resource(MusicUtil.getAafEndpointUrl().concat(nameSpace));
+ String plainCreds = userId + ":" + password;
+ byte[] plainCredsBytes = plainCreds.getBytes();
+ byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
+ String base64Creds = new String(base64CredsBytes);
+
+ ClientResponse response = webResource.accept(MediaType.APPLICATION_JSON)
+ .header("Authorization", "Basic " + base64Creds)
+ .header("content-type", "application/json").get(ClientResponse.class);
+ if (response.getStatus() != 200) {
+ if (userAttempts.get(nameSpace) == null)
+ userAttempts.put(nameSpace, 0);
+ if ((Integer) userAttempts.get(nameSpace) >= 2) {
+ lastFailedTime.put(nameSpace, Calendar.getInstance());
+ userAttempts.put(nameSpace, ((Integer) userAttempts.get(nameSpace) + 1));
+ throw new Exception(
+ "Reached max invalid attempts. Please contact admin and retry with valid credentials.");
+ }
+ userAttempts.put(nameSpace, ((Integer) userAttempts.get(nameSpace) + 1));
+ throw new Exception(
+ "Unable to authenticate. Please check the AAF credentials against namespace.");
+ // TODO Allow for 2-3 times and forbid any attempt to trigger AAF with invalid values
+ // for specific time.
+ }
+ response.getHeaders().put(HttpHeaders.CONTENT_TYPE,
+ Arrays.asList(MediaType.APPLICATION_JSON));
+ // AAFResponse output = response.getEntity(AAFResponse.class);
+ response.bufferEntity();
+ String x = response.getEntity(String.class);
+ AAFResponse responseObj = new ObjectMapper().readValue(x, AAFResponse.class);
+ return responseObj;
+ }
+
+ public static Map<String, Object> authenticateAIDUser(String aid, String keyspace)
+ throws Exception {
+ Map<String, Object> resultMap = new HashMap<>();
+ String uuid = null;
+ /*
+ * if(aid == null || aid.length() == 0) { resultMap.put("Exception Message",
+ * "AID is missing for the keyspace requested."); //create a new AID ?? } else
+ */
+ if (musicCache.get(keyspace) == null) {
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "SELECT uuid from admin.keyspace_master where keyspace_name = '"
+ + keyspace + "' allow filtering");
+ Row rs = MusicCore.get(pQuery).one();
+ try {
+ uuid = rs.getUUID("uuid").toString();
+ musicCache.put(keyspace, uuid);
+ } catch (Exception e) {
+ String msg = e.getMessage();
+ logger.error("Exception occured during uuid retrieval from DB." + e.getMessage());
+ resultMap.put("Exception", "Unauthorized operation. Check AID and Keyspace. "
+ + "Exception from MUSIC is: "
+ + (msg == null ? "Keyspace is new so no AID should be passed in Header."
+ : msg));
+ return resultMap;
+ }
+ if (!musicCache.get(keyspace).toString().equals(aid)) {
+ resultMap.put("Exception Message",
+ "Unauthorized operation. Invalid AID for the keyspace");
+ return resultMap;
+ }
+ } else if (musicCache.get(keyspace) != null
+ && !musicCache.get(keyspace).toString().equals(aid)) {
+ resultMap.put("Exception Message",
+ "Unauthorized operation. Invalid AID for the keyspace");
+ return resultMap;
+ }
+ resultMap.put("aid", uuid);
+ return resultMap;
+ }
+
+ public static void updateMusicCache(String aid, String keyspace) {
+ logger.info("Updating musicCache for keyspace " + keyspace + " with aid " + aid);
+ musicCache.put(keyspace, aid);
+ }
+
+ public static void updateisAAFCache(String namespace, String isAAF) {
+ appNameCache.put(namespace, isAAF);
+ }
+
+ public static Boolean isAAFApplication(String namespace) {
+
+ String isAAF = appNameCache.get(namespace);
+ if (isAAF == null) {
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "SELECT is_aaf from admin.keyspace_master where application_name = '"
+ + namespace + "' allow filtering");
+ Row rs = MusicCore.get(pQuery).one();
+ try {
+ isAAF = String.valueOf(rs.getBool("is_aaf"));
+ appNameCache.put(namespace, isAAF);
+ } catch (Exception e) {
+ logger.error("Exception occured during uuid retrieval from DB." + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ return Boolean.valueOf(isAAF);
+ }
+
+ public static String getUuidFromMusicCache(String keyspace) {
+ String uuid = musicCache.get(keyspace);
+ if (uuid == null) {
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "SELECT uuid from admin.keyspace_master where keyspace_name = '"
+ + keyspace + "' allow filtering");
+ Row rs = MusicCore.get(pQuery).one();
+ try {
+ uuid = rs.getUUID("uuid").toString();
+ musicCache.put(keyspace, uuid);
+ } catch (Exception e) {
+ logger.error("Exception occured during uuid retrieval from DB." + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+ return uuid;
+ }
+
+ public static String getAppName(String keyspace) {
+ String appName = null;
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "SELECT application_name from admin.keyspace_master where keyspace_name = '"
+ + keyspace + "' allow filtering");
+ Row rs = MusicCore.get(pQuery).one();
+ try {
+ appName = rs.getString("application_name");
+ } catch (Exception e) {
+ logger.error("Exception occured during uuid retrieval from DB." + e.getMessage());
+ e.printStackTrace();
+ }
+ return appName;
+ }
+
+ public static String generateUUID() {
+ String uuid = UUID.randomUUID().toString();
+ logger.info("New AID generated: " + uuid);
+ return uuid;
+ }
+
+ public static Map<String, Object> validateRequest(String nameSpace, String userId,
+ String password, String keyspace, String aid, String operation) {
+ Map<String, Object> resultMap = new HashMap<>();
+ if (!"createKeySpace".equals(operation)) {
+ if (nameSpace == null) {
+ resultMap.put("Exception", "Application namespace is mandatory.");
+ }
+ }
+ return resultMap;
+
+ }
+
+ public static Map<String, Object> verifyOnboarding(String ns, String userId, String password)
+ throws Exception {
+ Map<String, Object> resultMap = new HashMap<>();
+ if (ns == null || userId == null || password == null) {
+ logger.error("One or more required headers is missing. userId: " + userId
+ + " :: password: " + password);
+ resultMap.put("Exception",
+ "One or more required headers appName(ns), userId, password is missing. Please check.");
+ return resultMap;
+ }
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ queryObject.appendQueryString(
+ "select * from admin.keyspace_master where application_name=? and username=? allow filtering");
+ queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), ns));
+ queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
+ Row rs = MusicCore.get(queryObject).one();
+ if (rs == null) {
+ logger.error("Namespace and UserId doesn't match. namespace: " + ns + " and userId: "
+ + userId);
+ resultMap.put("Exception", "Application " + ns
+ + " doesn't seem to be Onboarded. Please onboard your application with MUSIC. If already onboarded contact Admin");
+ } else {
+ boolean is_aaf = rs.getBool("is_aaf");
+ String keyspace = rs.getString("keyspace_name");
+ if (!is_aaf) {
+ if (!keyspace.equals(MusicUtil.DEFAULTKEYSPACENAME)) {
+ logger.error("Non AAF applications are allowed to have only one keyspace per application.");
+ resultMap.put("Exception",
+ "Non AAF applications are allowed to have only one keyspace per application.");
+ }
+ }
+ }
+ return resultMap;
+ }
+}
diff --git a/src/main/java/org/onap/music/main/CronJobManager.java b/src/main/java/org/onap/music/main/CronJobManager.java
new file mode 100644
index 00000000..fb4a2ac3
--- /dev/null
+++ b/src/main/java/org/onap/music/main/CronJobManager.java
@@ -0,0 +1,47 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.main;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+
+@WebListener
+public class CronJobManager implements ServletContextListener {
+
+ private ScheduledExecutorService scheduler;
+
+ @Override
+ public void contextInitialized(ServletContextEvent event) {
+ scheduler = Executors.newSingleThreadScheduledExecutor();
+ scheduler.scheduleAtFixedRate(new CachingUtil(), 0, 24, TimeUnit.HOURS);
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent event) {
+ scheduler.shutdownNow();
+ }
+
+}
diff --git a/src/main/java/org/onap/music/main/MusicCore.java b/src/main/java/org/onap/music/main/MusicCore.java
new file mode 100644
index 00000000..592bae92
--- /dev/null
+++ b/src/main/java/org/onap/music/main/MusicCore.java
@@ -0,0 +1,874 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.main;
+
+
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+import org.onap.music.datastore.MusicDataStore;
+import org.onap.music.datastore.PreparedQueryObject;
+import org.onap.music.datastore.jsonobjects.JsonKeySpace;
+// import org.onap.music.eelf.logging.EELFLoggerDelegate;
+import org.onap.music.exceptions.MusicLockingException;
+import org.onap.music.exceptions.MusicQueryException;
+import org.onap.music.exceptions.MusicServiceException;
+import org.onap.music.lockingservice.MusicLockState;
+import org.onap.music.lockingservice.MusicLockState.LockStatus;
+import org.onap.music.lockingservice.MusicLockingService;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.datastax.driver.core.ColumnDefinitions;
+import com.datastax.driver.core.ColumnDefinitions.Definition;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.TableMetadata;
+
+/**
+ * This class .....
+ *
+ *
+ */
+public class MusicCore {
+
+ public static MusicLockingService mLockHandle = null;
+ public static MusicDataStore mDstoreHandle = null;
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(MusicCore.class);
+
+ public static class Condition {
+ Map<String, Object> conditions;
+ String selectQueryForTheRow;
+
+ public Condition(Map<String, Object> conditions, String selectQueryForTheRow) {
+ this.conditions = conditions;
+ this.selectQueryForTheRow = selectQueryForTheRow;
+ }
+
+ public boolean testCondition() {
+ // first generate the row
+ PreparedQueryObject query = new PreparedQueryObject();
+ query.appendQueryString(selectQueryForTheRow);
+ ResultSet results = quorumGet(query);
+ Row row = results.one();
+ return getDSHandle().doesRowSatisfyCondition(row, conditions);
+ }
+ }
+
+
+ public static MusicLockingService getLockingServiceHandle() throws MusicLockingException {
+ logger.info("Acquiring lock store handle");
+ long start = System.currentTimeMillis();
+
+ if (mLockHandle == null) {
+ try {
+ mLockHandle = new MusicLockingService();
+ } catch (Exception e) {
+ logger.error("Failed to aquire Locl store handle" + e.getMessage());
+ throw new MusicLockingException("Failed to aquire Locl store handle " + e);
+ }
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to acquire lock store handle:" + (end - start) + " ms");
+ return mLockHandle;
+ }
+
+ /**
+ *
+ * @param remoteIp
+ * @return
+ */
+ public static MusicDataStore getDSHandle(String remoteIp) {
+ logger.info("Acquiring data store handle");
+ long start = System.currentTimeMillis();
+ if (mDstoreHandle == null) {
+ mDstoreHandle = new MusicDataStore(remoteIp);
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to acquire data store handle:" + (end - start) + " ms");
+ return mDstoreHandle;
+ }
+
+ /**
+ *
+ * @return
+ */
+ public static MusicDataStore getDSHandle() {
+ logger.info("Acquiring data store handle");
+ long start = System.currentTimeMillis();
+ if (mDstoreHandle == null) {
+ mDstoreHandle = new MusicDataStore();
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to acquire data store handle:" + (end - start) + " ms");
+ return mDstoreHandle;
+ }
+
+ public static String createLockReference(String lockName) {
+ logger.info("Creating lock reference for lock name:" + lockName);
+ long start = System.currentTimeMillis();
+ String lockId = null;
+ try {
+ lockId = getLockingServiceHandle().createLockId("/" + lockName);
+ } catch (MusicLockingException e) {
+ logger.error("Failed to create Lock Reference " + lockName);
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to create lock reference:" + (end - start) + " ms");
+ return lockId;
+ }
+
+ /**
+ *
+ * @param key
+ * @return
+ */
+ public static boolean isTableOrKeySpaceLock(String key) {
+ String[] splitString = key.split("\\.");
+ if (splitString.length > 2)
+ return false;
+ else
+ return true;
+ }
+
+ /**
+ *
+ * @param key
+ * @return
+ */
+ public static MusicLockState getMusicLockState(String key) {
+ long start = System.currentTimeMillis();
+ try {
+ String[] splitString = key.split("\\.");
+ String keyspaceName = splitString[0];
+ String tableName = splitString[1];
+ String primaryKey = splitString[2];
+ MusicLockState mls;
+ String lockName = keyspaceName + "." + tableName + "." + primaryKey;
+ mls = getLockingServiceHandle().getLockState(lockName);
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to get lock state:" + (end - start) + " ms");
+ return mls;
+ } catch (NullPointerException | MusicLockingException e) {
+ logger.error("No lock object exists as of now.." + e);
+ }
+ return null;
+ }
+
+ public static ReturnType acquireLockWithLease(String key, String lockId, long leasePeriod) {
+ try {
+ long start = System.currentTimeMillis();
+ /* check if the current lock has exceeded its lease and if yes, release that lock */
+ MusicLockState mls = getMusicLockState(key);
+ if (mls != null) {
+ if (mls.getLockStatus().equals(LockStatus.LOCKED)) {
+ logger.info("The current lock holder for " + key + " is " + mls.getLockHolder()
+ + ". Checking if it has exceeded lease");
+ long currentLockPeriod = System.currentTimeMillis() - mls.getLeaseStartTime();
+ long currentLeasePeriod = mls.getLeasePeriod();
+ if (currentLockPeriod > currentLeasePeriod) {
+ logger.info("Lock period " + currentLockPeriod
+ + " has exceeded lease period " + currentLeasePeriod);
+ boolean voluntaryRelease = false;
+ String currentLockHolder = mls.getLockHolder();
+ mls = releaseLock(currentLockHolder, voluntaryRelease);
+ }
+ }
+ } else
+ logger.debug("There is no lock state object for " + key);
+
+ /*
+ * call the traditional acquire lock now and if the result returned is true, set the
+ * begin time-stamp and lease period
+ */
+ if (acquireLock(key, lockId) == true) {
+ mls = getMusicLockState(key);// get latest state
+ if (mls.getLeaseStartTime() == -1) {// set it again only if it is not set already
+ mls.setLeaseStartTime(System.currentTimeMillis());
+ mls.setLeasePeriod(leasePeriod);
+ getLockingServiceHandle().setLockState(key, mls);
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to acquire leased lock:" + (end - start) + " ms");
+ return new ReturnType(ResultType.SUCCESS, "Accquired lock");
+ } else {
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to fail to acquire leased lock:" + (end - start) + " ms");
+ return new ReturnType(ResultType.FAILURE, "Could not acquire lock");
+ }
+ } catch (Exception e) {
+ StringWriter sw = new StringWriter();
+ logger.error(e.getMessage());
+ String exceptionAsString = sw.toString();
+ return new ReturnType(ResultType.FAILURE,
+ "Exception thrown in acquireLockWithLease:\n" + exceptionAsString);
+ }
+ }
+
+ public static boolean acquireLock(String key, String lockId) {
+ /*
+ * first check if I am on top. Since ids are not reusable there is no need to check
+ * lockStatus If the status is unlocked, then the above call will automatically return
+ * false.
+ */
+ Boolean result = false;
+ try {
+ result = getLockingServiceHandle().isMyTurn(lockId);
+ } catch (MusicLockingException e2) {
+ logger.error("Failed to aquireLock lockId " + lockId + " " + e2);
+ }
+ if (result == false) {
+ logger.info("In acquire lock: Not your turn, someone else has the lock");
+ return false;
+ }
+
+
+ // this is for backward compatibility where locks could also be acquired on just
+ // keyspaces or tables.
+ if (isTableOrKeySpaceLock(key) == true) {
+ logger.info("In acquire lock: A table or keyspace lock so no need to perform sync...so returning true");
+ return true;
+ }
+
+ // read the lock name corresponding to the key and if the status is locked or being locked,
+ // then return false
+ MusicLockState currentMls = null;
+ MusicLockState newMls = null;
+ try {
+ currentMls = getMusicLockState(key);
+ String currentLockHolder = currentMls.getLockHolder();
+ if (lockId.equals(currentLockHolder)) {
+ logger.info("In acquire lock: You already have the lock!");
+ return true;
+ }
+ } catch (NullPointerException e) {
+ logger.error("In acquire lock:No one has tried to acquire the lock yet..");
+ }
+
+ // change status to "being locked". This state transition is necessary to ensure syncing
+ // before granting the lock
+ String lockHolder = null;
+ boolean needToSyncQuorum = false;
+ if (currentMls != null)
+ needToSyncQuorum = currentMls.isNeedToSyncQuorum();
+
+
+ newMls = new MusicLockState(MusicLockState.LockStatus.BEING_LOCKED, lockHolder,
+ needToSyncQuorum);
+ try {
+ getLockingServiceHandle().setLockState(key, newMls);
+ } catch (MusicLockingException e1) {
+ logger.error("Failed to set Lock state " + key + " " + e1);
+ }
+ logger.info("In acquire lock: Set lock state to being_locked");
+
+ // do syncing if this was a forced lock release
+ if (needToSyncQuorum) {
+ logger.info("In acquire lock: Since there was a forcible release, need to sync quorum!");
+ syncQuorum(key);
+ }
+
+ // change status to locked
+ lockHolder = lockId;
+ needToSyncQuorum = false;
+ newMls = new MusicLockState(MusicLockState.LockStatus.LOCKED, lockHolder, needToSyncQuorum);
+ try {
+ getLockingServiceHandle().setLockState(key, newMls);
+ } catch (MusicLockingException e) {
+ logger.error("Failed to set Lock state " + key + " " + e);
+ }
+ logger.info("In acquire lock: Set lock state to locked and assigned current lock ref "
+ + lockId + " as holder");
+ return result;
+ }
+
+
+
+ /**
+ *
+ * @param keyspaceName
+ * @param kspObject
+ * @return
+ * @throws Exception
+ */
+ public boolean createKeyspace(String keyspaceName, JsonKeySpace kspObject) throws Exception {
+ return true;
+ }
+
+
+ private static void syncQuorum(String key) {
+ logger.info("Performing sync operation---");
+ String[] splitString = key.split("\\.");
+ String keyspaceName = splitString[0];
+ String tableName = splitString[1];
+ String primaryKeyValue = splitString[2];
+ PreparedQueryObject selectQuery = new PreparedQueryObject();
+ PreparedQueryObject updateQuery = new PreparedQueryObject();
+
+ // get the primary key d
+ TableMetadata tableInfo = returnColumnMetadata(keyspaceName, tableName);
+ String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();// we only support single
+ // primary key
+ DataType primaryKeyType = tableInfo.getPrimaryKey().get(0).getType();
+ String cqlFormattedPrimaryKeyValue =
+ MusicUtil.convertToCQLDataType(primaryKeyType, primaryKeyValue);
+
+ // get the row of data from a quorum
+ selectQuery.appendQueryString("SELECT * FROM " + keyspaceName + "." + tableName + " WHERE "
+ + primaryKeyName + "= ?" + ";");
+ selectQuery.addValue(cqlFormattedPrimaryKeyValue);
+ // String selectQuery = "SELECT * FROM "+keyspaceName+"."+tableName+ " WHERE
+ // "+primaryKeyName+"="+cqlFormattedPrimaryKeyValue+";";
+ ResultSet results = null;
+ try {
+ results = getDSHandle().executeCriticalGet(selectQuery);
+ // write it back to a quorum
+ Row row = results.one();
+ ColumnDefinitions colInfo = row.getColumnDefinitions();
+ int totalColumns = colInfo.size();
+ int counter = 1;
+ // String fieldValueString="";
+ StringBuilder fieldValueString = new StringBuilder("");
+ for (Definition definition : colInfo) {
+ String colName = definition.getName();
+ if (colName.equals(primaryKeyName))
+ continue;
+ DataType colType = definition.getType();
+ Object valueObj = getDSHandle().getColValue(row, colName, colType);
+ String valueString = MusicUtil.convertToCQLDataType(colType, valueObj);
+ // fieldValueString = fieldValueString+ colName+"="+valueString;
+ fieldValueString.append(colName + " = ?");
+ updateQuery.addValue(valueString);
+ if (counter != (totalColumns - 1))
+ fieldValueString.append(",");
+ counter = counter + 1;
+ }
+ updateQuery.appendQueryString("UPDATE " + keyspaceName + "." + tableName + " SET "
+ + fieldValueString + " WHERE " + primaryKeyName + "= ? " + ";");
+ updateQuery.addValue(cqlFormattedPrimaryKeyValue);
+ // String updateQuery = "UPDATE "+keyspaceName+"."+tableName+" SET "+fieldValueString+"
+ // WHERE "+primaryKeyName+"="+cqlFormattedPrimaryKeyValue+";";
+
+ getDSHandle().executePut(updateQuery, "critical");
+ } catch (MusicServiceException | MusicQueryException e) {
+ logger.error("Failed to execute update query " + updateQuery + " " + e);
+ }
+ }
+
+
+ /**
+ * this function is mainly for the benchmarks to see the effect of lock deletion.
+ *
+ * @param keyspaceName
+ * @param tableName
+ * @param primaryKey
+ * @param queryObject
+ * @param conditionInfo
+ * @return
+ */
+ public static ReturnType atomicPutWithDeleteLock(String keyspaceName, String tableName,
+ String primaryKey, PreparedQueryObject queryObject, Condition conditionInfo) {
+ long start = System.currentTimeMillis();
+ String key = keyspaceName + "." + tableName + "." + primaryKey;
+ String lockId = createLockReference(key);
+ long lockCreationTime = System.currentTimeMillis();
+ long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
+ ReturnType lockAcqResult = acquireLockWithLease(key, lockId, leasePeriod);
+ long lockAcqTime = System.currentTimeMillis();
+ if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
+ logger.info("acquired lock with id " + lockId);
+ ReturnType criticalPutResult = criticalPut(keyspaceName, tableName, primaryKey,
+ queryObject, lockId, conditionInfo);
+ long criticalPutTime = System.currentTimeMillis();
+ deleteLock(key);
+ long lockDeleteTime = System.currentTimeMillis();
+ String timingInfo = "|lock creation time:" + (lockCreationTime - start)
+ + "|lock accquire time:" + (lockAcqTime - lockCreationTime)
+ + "|critical put time:" + (criticalPutTime - lockAcqTime)
+ + "|lock delete time:" + (lockDeleteTime - criticalPutTime) + "|";
+ criticalPutResult.setTimingInfo(timingInfo);
+ return criticalPutResult;
+ } else {
+ logger.info("unable to acquire lock, id " + lockId);
+ deleteLock(key);
+ return lockAcqResult;
+ }
+ }
+
+ /**
+ *
+ * @param query
+ * @return ResultSet
+ */
+ public static ResultSet quorumGet(PreparedQueryObject query) {
+ ResultSet results = null;
+ try {
+ results = getDSHandle().executeCriticalGet(query);
+ } catch (MusicServiceException | MusicQueryException e) {
+ logger.error(e.getMessage());
+ }
+ return results;
+
+ }
+
+ /**
+ *
+ * @param results
+ * @return
+ */
+ public static Map<String, HashMap<String, Object>> marshallResults(ResultSet results) {
+ return getDSHandle().marshalData(results);
+ }
+
+ /**
+ *
+ * @param lockName
+ * @return
+ */
+ public static String whoseTurnIsIt(String lockName) {
+
+ try {
+ return getLockingServiceHandle().whoseTurnIsIt("/" + lockName) + "";
+ } catch (MusicLockingException e) {
+ logger.error("Failed whoseTurnIsIt " + lockName + " " + e);
+ }
+ return null;
+
+
+ }
+
+ /**
+ *
+ * @param lockId
+ * @return
+ */
+ public static String getLockNameFromId(String lockId) {
+ StringTokenizer st = new StringTokenizer(lockId);
+ return st.nextToken("$");
+ }
+
+ public static void destroyLockRef(String lockId) {
+ long start = System.currentTimeMillis();
+ try {
+ getLockingServiceHandle().unlockAndDeleteId(lockId);
+ } catch (MusicLockingException e) {
+ logger.error("Failed to Destroy Lock Ref " + lockId + " " + e);
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to destroy lock reference:" + (end - start) + " ms");
+ }
+
+ public static MusicLockState releaseLock(String lockId, boolean voluntaryRelease) {
+ long start = System.currentTimeMillis();
+ try {
+ getLockingServiceHandle().unlockAndDeleteId(lockId);
+ } catch (MusicLockingException e1) {
+ logger.error("Failed to release Lock " + lockId + " " + e1);
+ }
+ String lockName = getLockNameFromId(lockId);
+ MusicLockState mls;
+ String lockHolder = null;
+ if (voluntaryRelease) {
+ mls = new MusicLockState(MusicLockState.LockStatus.UNLOCKED, lockHolder);
+ logger.info("In unlock: lock voluntarily released for " + lockId);
+ } else {
+ boolean needToSyncQuorum = true;
+ mls = new MusicLockState(MusicLockState.LockStatus.UNLOCKED, lockHolder,
+ needToSyncQuorum);
+ logger.info("In unlock: lock forcibly released for " + lockId);
+ }
+ try {
+ getLockingServiceHandle().setLockState(lockName, mls);
+ } catch (MusicLockingException e) {
+ logger.error("Failed to release Lock " + lockName + " " + e);
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to release lock:" + (end - start) + " ms");
+ return mls;
+ }
+
+ /**
+ *
+ * @param lockName
+ */
+ public static void deleteLock(String lockName) {
+ long start = System.currentTimeMillis();
+ logger.info("Deleting lock for " + lockName);
+ try {
+ getLockingServiceHandle().deleteLock("/" + lockName);
+ } catch (MusicLockingException e) {
+ logger.error("Failed to Delete Lock " + lockName + " " + e);
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken to delete lock:" + (end - start) + " ms");
+ }
+
+
+
+ /**
+ *
+ * @param keyspace
+ * @param tablename
+ * @return
+ */
+ public static TableMetadata returnColumnMetadata(String keyspace, String tablename) {
+ return getDSHandle().returnColumnMetadata(keyspace, tablename);
+ }
+
+
+ /**
+ *
+ * @param nodeName
+ */
+ public static void pureZkCreate(String nodeName) {
+ try {
+ getLockingServiceHandle().getzkLockHandle().createNode(nodeName);
+ } catch (MusicLockingException e) {
+ logger.error("Failed to get ZK Lock Handle " + e);
+ }
+ }
+
+ /**
+ *
+ * @param nodeName
+ * @param data
+ */
+ public static void pureZkWrite(String nodeName, byte[] data) {
+ long start = System.currentTimeMillis();
+ logger.info("Performing zookeeper write to " + nodeName);
+ try {
+ getLockingServiceHandle().getzkLockHandle().setNodeData(nodeName, data);
+ } catch (MusicLockingException e) {
+ logger.error("Failed to get ZK Lock Handle " + e);
+ }
+ logger.info("Performed zookeeper write to " + nodeName);
+ long end = System.currentTimeMillis();
+ logger.info("Time taken for the actual zk put:" + (end - start) + " ms");
+ }
+
+ /**
+ *
+ * @param nodeName
+ * @return
+ */
+ public static byte[] pureZkRead(String nodeName) {
+ long start = System.currentTimeMillis();
+ byte[] data = null;
+ try {
+ data = getLockingServiceHandle().getzkLockHandle().getNodeData(nodeName);
+ } catch (MusicLockingException e) {
+ logger.error("Failed to get ZK Lock Handle " + e);
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Time taken for the actual zk put:" + (end - start) + " ms");
+ return data;
+ }
+
+
+
+ // Prepared Query Additions.
+
+ /**
+ *
+ * @param keyspaceName
+ * @param tableName
+ * @param primaryKey
+ * @param queryObject
+ * @return ReturnType
+ * @throws MusicServiceException
+ */
+ public static ReturnType eventualPut(PreparedQueryObject queryObject) {
+ boolean result = false;
+ try {
+ result = getDSHandle().executePut(queryObject, MusicUtil.EVENTUAL);
+ } catch (MusicServiceException | MusicQueryException ex) {
+ logger.error(ex.getMessage() + " " + ex.getCause() + " " + ex);
+ }
+ if (result) {
+ return new ReturnType(ResultType.SUCCESS, "Success");
+ } else {
+ return new ReturnType(ResultType.FAILURE, "Failure");
+ }
+ }
+
+ /**
+ *
+ * @param keyspaceName
+ * @param tableName
+ * @param primaryKey
+ * @param queryObject
+ * @param lockId
+ * @return
+ */
+ public static ReturnType criticalPut(String keyspaceName, String tableName, String primaryKey,
+ PreparedQueryObject queryObject, String lockId, Condition conditionInfo) {
+ long start = System.currentTimeMillis();
+
+ try {
+ MusicLockState mls = getLockingServiceHandle()
+ .getLockState(keyspaceName + "." + tableName + "." + primaryKey);
+ if (mls.getLockHolder().equals(lockId) == true) {
+ if (conditionInfo != null)// check if condition is true
+ if (conditionInfo.testCondition() == false)
+ return new ReturnType(ResultType.FAILURE,
+ "Lock acquired but the condition is not true");
+ getDSHandle().executePut(queryObject, MusicUtil.CRITICAL);
+ long end = System.currentTimeMillis();
+ logger.info("Time taken for the critical put:" + (end - start) + " ms");
+ return new ReturnType(ResultType.SUCCESS, "Update performed");
+ } else
+ return new ReturnType(ResultType.FAILURE,
+ "Cannot perform operation since you are the not the lock holder");
+ } catch (MusicQueryException | MusicServiceException | MusicLockingException e) {
+ logger.error(e.getMessage());
+ return new ReturnType(ResultType.FAILURE,
+ "Exception thrown while doing the critical put, check sanctity of the row/conditions:\n"
+ + e.getMessage());
+ }
+
+ }
+
+ /**
+ *
+ * @param queryObject
+ * @param consistency
+ * @return Boolean Indicates success or failure
+ *
+ *
+ */
+ public static boolean nonKeyRelatedPut(PreparedQueryObject queryObject, String consistency) {
+ // this is mainly for some functions like keyspace creation etc which does not
+ // really need the bells and whistles of Music locking.
+ boolean result = false;
+ try {
+ result = getDSHandle().executePut(queryObject, consistency);
+ } catch (MusicQueryException | MusicServiceException ex) {
+ logger.error(ex.getMessage());
+ }
+ return result;
+ }
+
+ /**
+ * This method performs DDL operation on cassandra.
+ *
+ * @param queryObject query object containing prepared query and values
+ * @return ResultSet
+ */
+ public static ResultSet get(PreparedQueryObject queryObject) {
+ ResultSet results = null;
+ try {
+ results = getDSHandle().executeEventualGet(queryObject);
+ } catch (MusicQueryException | MusicServiceException e) {
+ logger.error(e.getMessage());
+ }
+ return results;
+ }
+
+ /**
+ * This method performs DDL operations on cassandra, if the the resource is available. Lock ID
+ * is used to check if the resource is free.
+ *
+ * @param keyspaceName name of the keyspace
+ * @param tableName name of the table
+ * @param primaryKey primary key value
+ * @param queryObject query object containing prepared query and values
+ * @param lockId lock ID to check if the resource is free to perform the operation.
+ * @return ResultSet
+ */
+ public static ResultSet criticalGet(String keyspaceName, String tableName, String primaryKey,
+ PreparedQueryObject queryObject, String lockId) throws MusicServiceException {
+ ResultSet results = null;
+ try {
+ MusicLockState mls = getLockingServiceHandle()
+ .getLockState(keyspaceName + "." + tableName + "." + primaryKey);
+ if (mls.getLockHolder().equals(lockId)) {
+ results = getDSHandle().executeCriticalGet(queryObject);
+ } else
+ throw new MusicServiceException("YOU DO NOT HAVE THE LOCK");
+ } catch (MusicQueryException | MusicServiceException | MusicLockingException e) {
+ logger.error(e.getMessage());
+ }
+ return results;
+ }
+
+ /**
+ * This method performs DML operation on cassandra, when the lock of the dd is acquired.
+ *
+ * @param keyspaceName name of the keyspace
+ * @param tableName name of the table
+ * @param primaryKey primary key value
+ * @param queryObject query object containing prepared query and values
+ * @return ReturnType
+ */
+ public static ReturnType atomicPut(String keyspaceName, String tableName, String primaryKey,
+ PreparedQueryObject queryObject, Condition conditionInfo) {
+ long start = System.currentTimeMillis();
+ String key = keyspaceName + "." + tableName + "." + primaryKey;
+ String lockId = createLockReference(key);
+ long lockCreationTime = System.currentTimeMillis();
+ long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
+ ReturnType lockAcqResult = acquireLockWithLease(key, lockId, leasePeriod);
+ long lockAcqTime = System.currentTimeMillis();
+ if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
+ logger.info("acquired lock with id " + lockId);
+ ReturnType criticalPutResult = criticalPut(keyspaceName, tableName, primaryKey,
+ queryObject, lockId, conditionInfo);
+ long criticalPutTime = System.currentTimeMillis();
+ boolean voluntaryRelease = true;
+ deleteLock(key);
+ long lockDeleteTime = System.currentTimeMillis();
+ String timingInfo = "|lock creation time:" + (lockCreationTime - start)
+ + "|lock accquire time:" + (lockAcqTime - lockCreationTime)
+ + "|critical put time:" + (criticalPutTime - lockAcqTime)
+ + "|lock delete time:" + (lockDeleteTime - criticalPutTime) + "|";
+ criticalPutResult.setTimingInfo(timingInfo);
+ return criticalPutResult;
+ } else {
+ logger.info("unable to acquire lock, id " + lockId);
+ destroyLockRef(lockId);
+ return lockAcqResult;
+ }
+ }
+
+
+ /**
+ * This method performs DDL operation on cassasndra, when the lock for the resource is acquired.
+ *
+ * @param keyspaceName name of the keyspace
+ * @param tableName name of the table
+ * @param primaryKey primary key value
+ * @param queryObject query object containing prepared query and values
+ * @return ResultSet
+ * @throws MusicServiceException
+ */
+ public static ResultSet atomicGet(String keyspaceName, String tableName, String primaryKey,
+ PreparedQueryObject queryObject) throws MusicServiceException {
+ String key = keyspaceName + "." + tableName + "." + primaryKey;
+ String lockId = createLockReference(key);
+ long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
+ ReturnType lockAcqResult = acquireLockWithLease(key, lockId, leasePeriod);
+ if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
+ logger.info("acquired lock with id " + lockId);
+ ResultSet result =
+ criticalGet(keyspaceName, tableName, primaryKey, queryObject, lockId);
+ boolean voluntaryRelease = true;
+ releaseLock(lockId, voluntaryRelease);
+ return result;
+ } else {
+ logger.info("unable to acquire lock, id " + lockId);
+ return null;
+ }
+ }
+
+ /**
+ * authenticate user logic
+ *
+ * @param nameSpace
+ * @param userId
+ * @param password
+ * @param keyspace
+ * @param aid
+ * @param operation
+ * @return
+ * @throws Exception
+ */
+ public static Map<String, Object> autheticateUser(String nameSpace, String userId,
+ String password, String keyspace, String aid, String operation)
+ throws Exception {
+ Map<String, Object> resultMap = new HashMap<>();
+ String uuid = null;
+ resultMap = CachingUtil.validateRequest(nameSpace, userId, password, keyspace, aid,
+ operation);
+ if (!resultMap.isEmpty())
+ return resultMap;
+ if (aid == null && (userId == null || password == null)) {
+ logger.error("One or more required headers is missing. userId: " + userId
+ + " :: password: " + password);
+ resultMap.put("Exception",
+ "UserId and Password are mandatory for the operation " + operation);
+ return resultMap;
+ }
+ boolean isAAF = CachingUtil.isAAFApplication(nameSpace);
+ if (!isAAF && aid != null && aid.length() > 0) { // Non AAF app
+ resultMap = CachingUtil.authenticateAIDUser(aid, keyspace);
+ if (!resultMap.isEmpty())
+ return resultMap;
+ }
+ if (isAAF && nameSpace != null && userId != null && password != null) {
+ boolean isValid = true;
+ try {
+ isValid = CachingUtil.authenticateAAFUser(nameSpace, userId, password, keyspace);
+ } catch (Exception e) {
+ logger.error("Got exception while AAF authentication for namespace " + nameSpace);
+ resultMap.put("Exception", e.getMessage());
+ // return resultMap;
+ }
+ if (!isValid) {
+ logger.error("User not authenticated with AAF.");
+ resultMap.put("Exception", "User not authenticated...");
+ // return resultMap;
+ }
+ if (!resultMap.isEmpty())
+ return resultMap;
+
+ }
+
+ if (operation.equals("createKeySpace")) {
+ logger.info("AID is not provided. Creating new UUID for keyspace.");
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "select uuid from admin.keyspace_master where application_name=? and username=? and keyspace_name=? allow filtering");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), nameSpace));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
+ MusicUtil.DEFAULTKEYSPACENAME));
+
+ try {
+ Row rs = MusicCore.get(pQuery).one();
+ uuid = rs.getUUID("uuid").toString();
+ resultMap.put("uuid", "existing");
+ } catch (Exception e) {
+ logger.info("No UUID found in DB. So creating new UUID.");
+ uuid = CachingUtil.generateUUID();
+ resultMap.put("uuid", "new");
+ }
+
+ pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "INSERT into admin.keyspace_master (uuid, keyspace_name, application_name, is_api, "
+ + "password, username, is_aaf) values (?,?,?,?,?,?,?)");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), keyspace));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), nameSpace));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True"));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), password));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
+ CachingUtil.updateMusicCache(uuid, keyspace);
+ MusicCore.eventualPut(pQuery);
+ resultMap.put("aid", uuid);
+ }
+
+ return resultMap;
+ }
+}
diff --git a/src/main/java/org/onap/music/main/MusicDigest.java b/src/main/java/org/onap/music/main/MusicDigest.java
new file mode 100644
index 00000000..893cb51f
--- /dev/null
+++ b/src/main/java/org/onap/music/main/MusicDigest.java
@@ -0,0 +1,78 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.main;
+
+/**
+ *
+ *
+ */
+public class MusicDigest {
+ private String evPutStatus;
+ private String vectorTs;
+
+ /**
+ * @param evPutStatus
+ * @param vectorTs
+ */
+ public MusicDigest(String evPutStatus, String vectorTs) {
+ this.evPutStatus = evPutStatus;
+ this.vectorTs = vectorTs;
+ }
+
+ /**
+ * @return
+ */
+ public String getEvPutStatus() {
+ return evPutStatus;
+ }
+
+ /**
+ * @param evPutStatus
+ */
+ public void setEvPutStatus(String evPutStatus) {
+ this.evPutStatus = evPutStatus;
+ }
+
+ /**
+ * @return
+ */
+ public String getVectorTs() {
+ return vectorTs;
+ }
+
+ /**
+ * @param vectorTs
+ */
+ public void setVectorTs(String vectorTs) {
+ this.vectorTs = vectorTs;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return vectorTs + "|" + evPutStatus;
+ }
+}
+
diff --git a/src/main/java/org/onap/music/main/MusicUtil.java b/src/main/java/org/onap/music/main/MusicUtil.java
new file mode 100755
index 00000000..61d428d1
--- /dev/null
+++ b/src/main/java/org/onap/music/main/MusicUtil.java
@@ -0,0 +1,465 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.main;
+
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.UUID;
+import org.onap.music.datastore.PreparedQueryObject;
+import org.onap.music.eelf.logging.EELFLoggerDelegate;
+import com.datastax.driver.core.DataType;
+
+/**
+ * @author nelson24
+ *
+ * Properties This will take Properties and load them into MusicUtil. This is a hack for
+ * now. Eventually it would bebest to do this in another way.
+ *
+ */
+public class MusicUtil {
+ private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MusicUtil.class);
+
+ private static int myId = 0;
+ private static ArrayList<String> allIds = new ArrayList<String>();
+ private static String publicIp = "";
+ private static ArrayList<String> allPublicIps = new ArrayList<String>();
+ private static String myZkHost = "localhost";
+ private static String myCassaHost = "localhost";
+ private static String defaultMusicIp = "localhost";
+ private static boolean debug = true;
+ private static String version = "2.3.0";
+ public static String musicRestIp = "localhost";
+ private static String musicPropertiesFilePath = "/opt/app/music/etc/music.properties";
+ private static long defaultLockLeasePeriod = 6000;
+ private static final String[] propKeys = new String[] {"zookeeper.host", "cassandra.host",
+ "music.ip", "debug", "version", "music.rest.ip", "music.properties",
+ "lock.lease.period", "id", "all.ids", "public.ip", "all.pubic.ips",
+ "cassandra.user", "cassandra.password", "aaf.endpoint.url"};
+
+ public static final String ATOMIC = "atomic";
+ public static final String EVENTUAL = "eventual";
+ public static final String CRITICAL = "critical";
+ public static final String DEFAULTKEYSPACENAME = "TBD";
+ private static String cassName = "cassandra";
+ private static String cassPwd = "cassandra";
+ private static String aafEndpointUrl = null;
+
+ /**
+ * @return the cassName
+ */
+ public static String getCassName() {
+ return cassName;
+ }
+
+ /**
+ * @return the cassPwd
+ */
+ public static String getCassPwd() {
+ return cassPwd;
+ }
+
+ /**
+ * @return the aafEndpointUrl
+ */
+ public static String getAafEndpointUrl() {
+ return aafEndpointUrl;
+ }
+
+ /**
+ *
+ * @param aafEndpointUrl
+ */
+ public static void setAafEndpointUrl(String aafEndpointUrl) {
+ MusicUtil.aafEndpointUrl = aafEndpointUrl;
+ }
+
+ /**
+ *
+ * @return
+ */
+ public static int getMyId() {
+ return myId;
+ }
+
+ /**
+ *
+ * @param myId
+ */
+ public static void setMyId(int myId) {
+ MusicUtil.myId = myId;
+ }
+
+
+ /**
+ *
+ * @return
+ */
+ public static ArrayList<String> getAllIds() {
+ return allIds;
+ }
+
+ /**
+ *
+ * @param allIds
+ */
+ public static void setAllIds(List<String> allIds) {
+ MusicUtil.allIds = (ArrayList<String>) allIds;
+ }
+
+ /**
+ *
+ * @return
+ */
+ public static String getPublicIp() {
+ return publicIp;
+ }
+
+ /**
+ *
+ * @param publicIp
+ */
+ public static void setPublicIp(String publicIp) {
+ MusicUtil.publicIp = publicIp;
+ }
+
+ /**
+ *
+ * @return
+ */
+ public static ArrayList<String> getAllPublicIps() {
+ return allPublicIps;
+ }
+
+ /**
+ *
+ * @param allPublicIps
+ */
+ public static void setAllPublicIps(List<String> allPublicIps) {
+ MusicUtil.allPublicIps = (ArrayList<String>) allPublicIps;
+ }
+
+ /**
+ * Returns An array of property names that should be in the Properties files.
+ *
+ * @return
+ */
+ public static String[] getPropkeys() {
+ return propKeys;
+ }
+
+ /**
+ * Get MusicRestIp - default = localhost property file value - music.rest.ip
+ *
+ * @return
+ */
+ public static String getMusicRestIp() {
+ return musicRestIp;
+ }
+
+ /**
+ * Set MusicRestIp
+ *
+ * @param musicRestIp
+ */
+ public static void setMusicRestIp(String musicRestIp) {
+ MusicUtil.musicRestIp = musicRestIp;
+ }
+
+ /**
+ * Get MusicPropertiesFilePath - Default = /opt/music/music.properties property file value -
+ * music.properties
+ *
+ * @return
+ */
+ public static String getMusicPropertiesFilePath() {
+ return musicPropertiesFilePath;
+ }
+
+ /**
+ * Set MusicPropertiesFilePath
+ *
+ * @param musicPropertiesFilePath
+ */
+ public static void setMusicPropertiesFilePath(String musicPropertiesFilePath) {
+ MusicUtil.musicPropertiesFilePath = musicPropertiesFilePath;
+ }
+
+ /**
+ * Get DefaultLockLeasePeriod - Default = 6000 property file value - lock.lease.period
+ *
+ * @return
+ */
+ public static long getDefaultLockLeasePeriod() {
+ return defaultLockLeasePeriod;
+ }
+
+ /**
+ * Set DefaultLockLeasePeriod
+ *
+ * @param defaultLockLeasePeriod
+ */
+ public static void setDefaultLockLeasePeriod(long defaultLockLeasePeriod) {
+ MusicUtil.defaultLockLeasePeriod = defaultLockLeasePeriod;
+ }
+
+ /**
+ * Set Debug
+ *
+ * @param debug
+ */
+ public static void setDebug(boolean debug) {
+ MusicUtil.debug = debug;
+ }
+
+ /**
+ * Is Debug - Default = true property file value - debug
+ *
+ * @return
+ */
+ public static boolean isDebug() {
+ return debug;
+ }
+
+ /**
+ * Set Version
+ *
+ * @param version
+ */
+ public static void setVersion(String version) {
+ MusicUtil.version = version;
+ }
+
+ /**
+ * Return the version property file value - version
+ *
+ * @return
+ */
+ public static String getVersion() {
+ return version;
+ }
+
+ /**
+ * Get MyZkHost - Zookeeper Hostname - Default = localhost property file value - zookeeper.host
+ *
+ * @return
+ */
+ public static String getMyZkHost() {
+ return myZkHost;
+ }
+
+ /**
+ * Set MyZkHost - Zookeeper Hostname
+ *
+ * @param myZkHost
+ */
+ public static void setMyZkHost(String myZkHost) {
+ MusicUtil.myZkHost = myZkHost;
+ }
+
+ /**
+ * Get MyCassHost - Cassandra Hostname - Default = localhost property file value -
+ * cassandra.host
+ *
+ * @return
+ */
+ public static String getMyCassaHost() {
+ return myCassaHost;
+ }
+
+ /**
+ * Set MyCassHost - Cassandra Hostname
+ *
+ * @param myCassaHost
+ */
+ public static void setMyCassaHost(String myCassaHost) {
+ MusicUtil.myCassaHost = myCassaHost;
+ }
+
+ /**
+ * Get DefaultMusicIp - Default = localhost property file value - music.ip
+ *
+ * @return
+ */
+ public static String getDefaultMusicIp() {
+ return defaultMusicIp;
+ }
+
+ /**
+ * Set DefaultMusicIp
+ *
+ * @param defaultMusicIp
+ */
+ public static void setDefaultMusicIp(String defaultMusicIp) {
+ MusicUtil.defaultMusicIp = defaultMusicIp;
+ }
+
+ /**
+ *
+ * @return
+ */
+ public static String getTestType() {
+ String testType = "";
+ try {
+ Scanner fileScanner = new Scanner(new File(""));
+ testType = fileScanner.next();// ignore the my id line
+ String batchSize = fileScanner.next();// ignore the my public ip line
+ fileScanner.close();
+ } catch (FileNotFoundException e) {
+ logger.error(EELFLoggerDelegate.errorLogger, e.getMessage());
+ }
+ return testType;
+
+ }
+
+ /**
+ *
+ * @param time
+ */
+ public static void sleep(long time) {
+ try {
+ Thread.sleep(time);
+ } catch (InterruptedException e) {
+ logger.error(EELFLoggerDelegate.errorLogger, e.getMessage());
+ }
+ }
+
+ /**
+ * Utility function to check if the query object is valid.
+ *
+ * @param withparams
+ * @param queryObject
+ * @return
+ */
+ public static boolean isValidQueryObject(boolean withparams, PreparedQueryObject queryObject) {
+ if (withparams) {
+ int noOfValues = queryObject.getValues().size();
+ int noOfParams = 0;
+ char[] temp = queryObject.getQuery().toCharArray();
+ for (int i = 0; i < temp.length; i++) {
+ if (temp[i] == '?')
+ noOfParams++;
+ }
+ return (noOfValues == noOfParams);
+ } else {
+ return !queryObject.getQuery().isEmpty();
+ }
+
+ }
+
+ public static void setCassName(String cassName) {
+ MusicUtil.cassName = cassName;
+ }
+
+ public static void setCassPwd(String cassPwd) {
+ MusicUtil.cassPwd = cassPwd;
+ }
+
+ public static String convertToCQLDataType(DataType type, Object valueObj) {
+
+ String value = "";
+ switch (type.getName()) {
+ case UUID:
+ value = valueObj + "";
+ break;
+ case TEXT:
+ case VARCHAR:
+ String valueString = valueObj + "";
+ valueString = valueString.replace("'", "''");
+ value = "'" + valueString + "'";
+ break;
+ case MAP: {
+ Map<String, Object> otMap = (Map<String, Object>) valueObj;
+ value = "{" + jsonMaptoSqlString(otMap, ",") + "}";
+ break;
+ }
+ default:
+ value = valueObj + "";
+ break;
+ }
+ return value;
+ }
+
+
+ /**
+ *
+ * @param colType
+ * @param valueObj
+ * @return
+ * @throws Exception
+ */
+ public static Object convertToActualDataType(DataType colType, Object valueObj) {
+ String valueObjString = valueObj + "";
+ switch (colType.getName()) {
+ case UUID:
+ return UUID.fromString(valueObjString);
+ case VARINT:
+ return BigInteger.valueOf(Long.parseLong(valueObjString));
+ case BIGINT:
+ return Long.parseLong(valueObjString);
+ case INT:
+ return Integer.parseInt(valueObjString);
+ case FLOAT:
+ return Float.parseFloat(valueObjString);
+ case DOUBLE:
+ return Double.parseDouble(valueObjString);
+ case BOOLEAN:
+ return Boolean.parseBoolean(valueObjString);
+ case MAP:
+ return (Map<String, Object>) valueObj;
+ default:
+ return valueObjString;
+ }
+ }
+
+
+ /**
+ *
+ * Utility function to parse json map into sql like string
+ *
+ * @param jMap
+ * @param lineDelimiter
+ * @return
+ */
+
+ public static String jsonMaptoSqlString(Map<String, Object> jMap, String lineDelimiter) {
+ StringBuilder sqlString = new StringBuilder();
+ int counter = 0;
+ for (Map.Entry<String, Object> entry : jMap.entrySet()) {
+ Object ot = entry.getValue();
+ String value = ot + "";
+ if (ot instanceof String) {
+ value = "'" + value.replace("'", "''") + "'";
+ }
+ sqlString.append("'" + entry.getKey() + "':" + value);
+ if (counter != jMap.size() - 1)
+ sqlString.append(lineDelimiter);
+ counter = counter + 1;
+ }
+ return sqlString.toString();
+ }
+}
diff --git a/src/main/java/org/onap/music/main/PropertiesListener.java b/src/main/java/org/onap/music/main/PropertiesListener.java
new file mode 100755
index 00000000..de231542
--- /dev/null
+++ b/src/main/java/org/onap/music/main/PropertiesListener.java
@@ -0,0 +1,147 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.main;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Properties;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+import org.onap.music.eelf.logging.EELFLoggerDelegate;
+
+@WebListener
+public class PropertiesListener implements ServletContextListener {
+ private Properties prop;
+
+ private static EELFLoggerDelegate logger =
+ EELFLoggerDelegate.getLogger(PropertiesListener.class);
+
+ @Override
+ public void contextInitialized(ServletContextEvent servletContextEvent) {
+ prop = new Properties();
+ Properties projectProp = new Properties();
+ URL resource = getClass().getResource("/");
+ String musicPropertiesFilePath = resource.getPath().replace("WEB-INF/classes/",
+ "WEB-INF/classes/project.properties");
+
+ // Open the file
+ try {
+ InputStream musicProps = null;
+ projectProp.load(new FileInputStream(musicPropertiesFilePath));
+ if (projectProp.containsKey("music.properties")) {
+ musicProps = new FileInputStream(projectProp.getProperty("music.properties"));
+ } else {
+ musicProps = new FileInputStream(MusicUtil.getMusicPropertiesFilePath());
+ }
+ prop.load(musicProps);
+ musicProps.close();
+ prop.putAll(projectProp);
+ String[] propKeys = MusicUtil.getPropkeys();
+ for (int k = 0; k < propKeys.length; k++) {
+ String key = propKeys[k];
+ if (prop.containsKey(key) && prop.get(key) != null) {
+ logger.info(key + " : " + prop.getProperty(key));
+ switch (key) {
+ case "zookeeper.host":
+ MusicUtil.setMyZkHost(prop.getProperty(key));
+ break;
+ case "cassandra.host":
+ MusicUtil.setMyCassaHost(prop.getProperty(key));
+ break;
+ case "music.ip":
+ MusicUtil.setDefaultMusicIp(prop.getProperty(key));
+ break;
+ case "debug":
+ MusicUtil.setDebug(Boolean
+ .getBoolean(prop.getProperty(key).toLowerCase()));
+ break;
+ case "version":
+ MusicUtil.setVersion(prop.getProperty(key));
+ break;
+ case "music.rest.ip":
+ MusicUtil.setMusicRestIp(prop.getProperty(key));
+ break;
+ case "music.properties":
+ MusicUtil.setMusicPropertiesFilePath(prop.getProperty(key));
+ break;
+ case "lock.lease.period":
+ MusicUtil.setDefaultLockLeasePeriod(
+ Long.parseLong(prop.getProperty(key)));
+ break;
+ case "my.id":
+ MusicUtil.setMyId(Integer.parseInt(prop.getProperty(key)));
+ break;
+ case "all.ids":
+ String[] ids = prop.getProperty(key).split(":");
+ MusicUtil.setAllIds(new ArrayList<String>(Arrays.asList(ids)));
+ break;
+ case "public.ip":
+ MusicUtil.setPublicIp(prop.getProperty(key));
+ break;
+ case "all.public.ips":
+ String[] ips = prop.getProperty(key).split(":");
+ if (ips.length == 1) {
+ // Future use
+ } else if (ips.length > 1) {
+ MusicUtil.setAllPublicIps(
+ new ArrayList<String>(Arrays.asList(ips)));
+ }
+ break;
+ case "cassandra.user":
+ MusicUtil.setCassName(prop.getProperty(key));
+ break;
+ case "cassandra.password":
+ MusicUtil.setCassPwd(prop.getProperty(key));
+ break;
+ case "aaf.endpoint.url":
+ MusicUtil.setAafEndpointUrl(prop.getProperty(key));
+ break;
+ default:
+ logger.error(EELFLoggerDelegate.errorLogger,
+ "No case found for " + key);
+ }
+ }
+ }
+ } catch (IOException e) {
+ logger.error(EELFLoggerDelegate.errorLogger, e.getMessage());
+ }
+
+ logger.info(EELFLoggerDelegate.applicationLogger,
+ "Starting MUSIC " + MusicUtil.getVersion() + " on node with id "
+ + MusicUtil.getMyId() + " and public ip "
+ + MusicUtil.getPublicIp() + "...");
+ logger.info(EELFLoggerDelegate.applicationLogger,
+ "List of all MUSIC ids:" + MusicUtil.getAllIds().toString());
+ logger.info(EELFLoggerDelegate.applicationLogger,
+ "List of all MUSIC public ips:" + MusicUtil.getAllPublicIps().toString());
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent servletContextEvent) {
+ prop = null;
+ }
+}
diff --git a/src/main/java/org/onap/music/main/ResultType.java b/src/main/java/org/onap/music/main/ResultType.java
new file mode 100644
index 00000000..f19ada4a
--- /dev/null
+++ b/src/main/java/org/onap/music/main/ResultType.java
@@ -0,0 +1,39 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.main;
+
+public enum ResultType {
+ SUCCESS("Success"), FAILURE("Failure");
+
+ private String result;
+
+ ResultType(String result) {
+ this.result = result;
+ }
+
+ public String getResult() {
+ return result;
+ }
+
+}
+
+
diff --git a/src/main/java/org/onap/music/main/ReturnType.java b/src/main/java/org/onap/music/main/ReturnType.java
new file mode 100644
index 00000000..1453a1bf
--- /dev/null
+++ b/src/main/java/org/onap/music/main/ReturnType.java
@@ -0,0 +1,74 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.main;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ReturnType {
+ private ResultType result;
+ private String message;
+
+ public ReturnType(ResultType result, String message) {
+ super();
+ this.result = result;
+ this.message = message;
+ }
+
+ public String getTimingInfo() {
+ return timingInfo;
+ }
+
+ public void setTimingInfo(String timingInfo) {
+ this.timingInfo = timingInfo;
+ }
+
+ private String timingInfo;
+
+ public ResultType getResult() {
+ return result;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public String toJson() {
+ return "{ \"result\":\"" + result.getResult() + "\", \"message\":\"" + message + "\"}";
+ }
+
+ public String toString() {
+ return result + " | " + message;
+ }
+
+ public Map<String, Object> toMap() {
+ Map<String, Object> newMap = new HashMap<>();
+ newMap.put("result", result.getResult());
+ newMap.put("message", message);
+ return newMap;
+ }
+
+}
diff --git a/src/main/java/org/onap/music/response/jsonobjects/JsonLockResponse.java b/src/main/java/org/onap/music/response/jsonobjects/JsonLockResponse.java
new file mode 100644
index 00000000..875fbbba
--- /dev/null
+++ b/src/main/java/org/onap/music/response/jsonobjects/JsonLockResponse.java
@@ -0,0 +1,258 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.response.jsonobjects;
+
+import java.util.HashMap;
+import java.util.Map;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonResponse", description = "General Response JSON")
+public class JsonLockResponse {
+
+ private String status = "";
+ private String error = "";
+ private String message = "";
+ private String lock = "";
+ private String lockStatus = "";
+ private String lockHolder = "";
+ private String lockLease = "";
+
+ /**
+ *
+ * @param status
+ * @param error
+ * @param lock
+ */
+ public JsonLockResponse(String status, String error, String lock) {
+ this.status = fixStatus(status);
+ this.error = error;
+ this.lock = lock;
+ }
+
+ /**
+ *
+ * @param status
+ * @param error
+ * @param lock
+ * @param lockStatus
+ * @param lockHolder
+ */
+ public JsonLockResponse(String status, String error, String lock, String lockStatus,
+ String lockHolder) {
+ this.status = fixStatus(status);
+ this.error = error;
+ this.lock = lock;
+ this.lockStatus = lockStatus;
+ this.lockHolder = lockHolder;
+ }
+
+ /**
+ *
+ * @param status
+ * @param error
+ * @param lock
+ * @param lockStatus
+ * @param lockHolder
+ * @param lockLease
+ */
+ public JsonLockResponse(String status, String error, String lock, String lockStatus,
+ String lockHolder, String lockLease) {
+ this.status = fixStatus(status);
+ this.error = error;
+ this.lock = lock;
+ this.lockStatus = lockStatus;
+ this.lockHolder = lockHolder;
+ }
+
+
+ /**
+ * Lock
+ *
+ * @return
+ */
+ public String getLock() {
+ return lock;
+ }
+
+ /**
+ *
+ * @param lock
+ */
+ public void setLock(String lock) {
+ this.lock = lock;
+ }
+
+ /**
+ *
+ */
+ public JsonLockResponse() {
+ this.status = "";
+ this.error = "";
+ }
+
+ /**
+ *
+ * @param statusIn
+ * @return
+ */
+ private String fixStatus(String statusIn) {
+ if (statusIn.equalsIgnoreCase("false")) {
+ return "FAILURE";
+ }
+ return "SUCCESS";
+ }
+
+ /**
+ *
+ * @return
+ */
+ @ApiModelProperty(value = "Overall status of the response.",
+ allowableValues = "Success,Failure")
+ public String getStatus() {
+ return status;
+ }
+
+ /**
+ *
+ * @param status
+ */
+ public void setStatus(String status) {
+ this.status = fixStatus(status);
+ }
+
+ /**
+ *
+ * @return the error
+ */
+ @ApiModelProperty(value = "Error value")
+ public String getError() {
+ return error;
+ }
+
+ /**
+ *
+ * @param error
+ */
+ public void setError(String error) {
+ this.error = error;
+ }
+
+ /**
+ *
+ * @return the message
+ */
+ @ApiModelProperty(value = "Message if any need to be conveyed about the lock")
+ public String getMessage() {
+ return message;
+ }
+
+ /**
+ *
+ * @param message
+ */
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ /**
+ *
+ * @return the lockStatus
+ */
+ @ApiModelProperty(value = "Status of the lock",
+ allowableValues = "UNLOCKED,BEING_LOCKED,LOCKED")
+ public String getLockStatus() {
+ return lockStatus;
+ }
+
+ /**
+ *
+ * @param lockStatus
+ */
+ public void setLockStatus(String lockStatus) {
+ this.lockStatus = lockStatus;
+ }
+
+ /**
+ *
+ *
+ * @return the lockHolder
+ */
+ @ApiModelProperty(value = "Holder of the Lock")
+ public String getLockHolder() {
+ return lockHolder;
+ }
+
+ /**
+ *
+ * @param lockHolder
+ */
+ public void setLockHolder(String lockHolder) {
+ this.lockHolder = lockHolder;
+ }
+
+
+
+ /**
+ * @return the lockLease
+ */
+ public String getLockLease() {
+ return lockLease;
+ }
+
+ /**
+ * @param lockLease the lockLease to set
+ */
+ public void setLockLease(String lockLease) {
+ this.lockLease = lockLease;
+ }
+
+ /**
+ * Convert to Map
+ *
+ * @return
+ */
+ public Map<String, Object> toMap() {
+ Map<String, Object> newMap = new HashMap<>();
+ Map<String, Object> lockMap = new HashMap<>();
+ lockMap.put("lock-status", lockStatus);
+ lockMap.put("lock", lock);
+ lockMap.put("message", message);
+ lockMap.put("lock-holder", lockHolder);
+ lockMap.put("lock-lease", lockLease);
+ newMap.put("status", status);
+ newMap.put("error", error);
+ newMap.put("lock", lockMap);
+ return newMap;
+ }
+
+ /**
+ * Convert to String
+ */
+ @Override
+ public String toString() {
+ return "JsonLockResponse [status=" + status + ", error=" + error + ", message=" + message
+ + ", lock=" + lock + ", lockStatus=" + lockStatus + ", lockHolder="
+ + lockHolder + "]";
+ }
+
+}
diff --git a/src/main/java/org/onap/music/response/jsonobjects/JsonResponse.java b/src/main/java/org/onap/music/response/jsonobjects/JsonResponse.java
new file mode 100644
index 00000000..d44f9fe7
--- /dev/null
+++ b/src/main/java/org/onap/music/response/jsonobjects/JsonResponse.java
@@ -0,0 +1,95 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.response.jsonobjects;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+@ApiModel(value = "JsonResponse", description = "General Response JSON")
+public class JsonResponse {
+
+ private Boolean status = false;
+ private String error = "";
+ private String version = "";
+
+ public JsonResponse(Boolean status, String error, String version) {
+ this.status = status;
+ this.error = error;
+ this.version = version;
+ }
+
+ public JsonResponse() {
+ this.status = false;
+ this.error = "";
+ this.version = "";
+ }
+
+ @ApiModelProperty(value = "Status value")
+ public Boolean getStatus() {
+ return status;
+ }
+
+ /**
+ *
+ * @param statusIn
+ * @return
+ */
+ private String fixStatus(String statusIn) {
+ if (statusIn.equalsIgnoreCase("false")) {
+ return "FAILURE";
+ }
+ return "SUCCESS";
+ }
+
+ public void setStatus(Boolean status) {
+ this.status = status;
+ }
+
+ @ApiModelProperty(value = "Error value")
+ public String getError() {
+ return error;
+ }
+
+ public void setError(String error) {
+ this.error = error;
+ }
+
+ @ApiModelProperty(value = "Version value")
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public Map<String, Object> toMap() {
+ Map<String, Object> newMap = new HashMap<>();
+ newMap.put("status", fixStatus(String.valueOf(status)));
+ newMap.put("error", error);
+ newMap.put("version", version);
+ return newMap;
+ }
+}
diff --git a/src/main/java/org/onap/music/rest/RestMusicAdminAPI.java b/src/main/java/org/onap/music/rest/RestMusicAdminAPI.java
new file mode 100755
index 00000000..87a3a1ba
--- /dev/null
+++ b/src/main/java/org/onap/music/rest/RestMusicAdminAPI.java
@@ -0,0 +1,305 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.rest;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import org.onap.music.datastore.PreparedQueryObject;
+import org.onap.music.datastore.jsonobjects.JsonOnboard;
+import org.onap.music.main.CachingUtil;
+import org.onap.music.main.MusicCore;
+import org.onap.music.main.MusicUtil;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+
+@Path("/v{version: [0-9]+}/admin")
+// @Path("/admin")
+@Api(value = "Admin Api", hidden = true)
+public class RestMusicAdminAPI {
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(RestMusicAdminAPI.class);
+
+ /*
+ * API to onboard an application with MUSIC. This is the mandatory first step.
+ *
+ */
+ @POST
+ @Path("/onboardAppWithMusic")
+ @ApiOperation(value = "Onboard application", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> onboardAppWithMusic(JsonOnboard jsonObj,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = new HashMap<>();
+ String appName = jsonObj.getAppname();
+ String userId = jsonObj.getUserId();
+ String isAAF = jsonObj.getIsAAF();
+ String password = jsonObj.getPassword();
+ response.addHeader("X-latestVersion", MusicUtil.getVersion());
+ if (appName == null || userId == null || isAAF == null || password == null) {
+ resultMap.put("Exception",
+ "Please check the request parameters. Some of the required values appName(ns), userId, password, isAAF are missing.");
+ return resultMap;
+ }
+
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "select uuid from admin.keyspace_master where application_name = ? allow filtering");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
+ ResultSet rs = MusicCore.get(pQuery);
+ if (!rs.all().isEmpty()) {
+ resultMap.put("Exception", "Your application " + appName
+ + " has already been onboarded. Please contact admin.");
+ return resultMap;
+ }
+
+ pQuery = new PreparedQueryObject();
+ String uuid = CachingUtil.generateUUID();
+ pQuery.appendQueryString(
+ "INSERT INTO admin.keyspace_master (uuid, keyspace_name, application_name, is_api, "
+ + "password, username, is_aaf) VALUES (?,?,?,?,?,?,?)");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
+ MusicUtil.DEFAULTKEYSPACENAME));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), "True"));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), password));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
+
+ String returnStr = MusicCore.eventualPut(pQuery).toString();
+ if (returnStr.contains("Failure")) {
+ resultMap.put("Exception",
+ "Oops. Something wrong with onboarding process. Please retry later or contact admin.");
+ return resultMap;
+ }
+ CachingUtil.updateisAAFCache(appName, isAAF);
+ resultMap.put("Success", "Your application " + appName + " has been onboarded with MUSIC.");
+ resultMap.put("Generated AID", uuid);
+ return resultMap;
+ }
+
+
+ /*
+ * API to onboard an application with MUSIC. This is the mandatory first step.
+ *
+ */
+ @GET
+ @Path("/onboardAppWithMusic")
+ @ApiOperation(value = "Onboard application", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> getOnboardedInfo(
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String uuid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String appName,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = new HashMap<>();
+
+ response.addHeader("X-latestVersion", MusicUtil.getVersion());
+ if (appName == null && uuid == null) {
+ resultMap.put("Exception",
+ "Please check the request parameters. Some of the required values appName(ns), aid are missing.");
+ return resultMap;
+ }
+
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+
+ String cql = "select uuid, keyspace_name from admin.keyspace_master where ";
+ if (appName != null)
+ cql = cql + "application_name = ?";
+ else if (uuid != null)
+ cql = cql + "uuid = ?";
+ cql = cql + " allow filtering";
+ System.out.println("Get OnboardingInfo CQL: " + cql);
+ pQuery.appendQueryString(cql);
+ if (appName != null)
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
+ else if (uuid != null)
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
+ ResultSet rs = MusicCore.get(pQuery);
+ Iterator<Row> it = rs.iterator();
+ while (it.hasNext()) {
+ Row row = (Row) it.next();
+ resultMap.put(row.getString("keyspace_name"), row.getUUID("uuid"));
+ }
+ if (resultMap.isEmpty())
+ resultMap.put("ERROR", "Application is not onboarded. Please contact admin.");
+ return resultMap;
+ }
+
+
+ @DELETE
+ @Path("/onboardAppWithMusic")
+ @ApiOperation(value = "Delete Onboard application", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> deleteOnboardApp(JsonOnboard jsonObj,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = new HashMap<>();
+ response.addHeader("X-latestVersion", MusicUtil.getVersion());
+ String appName = jsonObj.getAppname();
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ long count = 0;
+ if (appName == null && aid == null) {
+ resultMap.put("Exception", "Please make sure either appName(ns) or Aid is present");
+ return resultMap;
+ }
+ if (aid != null) {
+ pQuery.appendQueryString(
+ "select count(*) as count from admin.keyspace_master where uuid = ?");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
+ UUID.fromString(aid)));
+ Row row = MusicCore.get(pQuery).one();
+ if (row != null) {
+ count = row.getLong(0);
+ }
+
+ if (count == 0) {
+ resultMap.put("Failure", "Please verify your AID.");
+ return resultMap;
+ } else {
+ pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ?");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
+ UUID.fromString(aid)));
+ String result = MusicCore.eventualPut(pQuery).toString();
+ if (result.toLowerCase().contains("success")) {
+ resultMap.put("Success", "Your application has been deleted.");
+ return resultMap;
+ } else {
+ resultMap.put("Failure", "Please verify your AID.");
+ return resultMap;
+ }
+ }
+
+ }
+ pQuery.appendQueryString(
+ "select uuid from admin.keyspace_master where application_name = ? allow filtering");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
+ ResultSet rs = MusicCore.get(pQuery);
+ List<Row> rows = rs.all();
+ String uuid = null;
+ if (rows.size() == 0) {
+ resultMap.put("Exception",
+ "Application not found. Please make sure Application exists.");
+ return resultMap;
+ } else if (rows.size() == 1) {
+ uuid = rows.get(0).getUUID("uuid").toString();
+ pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ?");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(),
+ UUID.fromString(uuid)));
+ MusicCore.eventualPut(pQuery);
+ resultMap.put("Success", "Your application " + appName + " has been deleted.");
+ return resultMap;
+ } else {
+ resultMap.put("Failure", "Please provide UUID for the application.");
+ }
+
+ return resultMap;
+ }
+
+
+ @PUT
+ @Path("/onboardAppWithMusic")
+ @ApiOperation(value = "Update Onboard application", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> updateOnboardApp(JsonOnboard jsonObj,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = new HashMap<>();
+ response.addHeader("X-latestVersion", MusicUtil.getVersion());
+ String appName = jsonObj.getAppname();
+ String userId = jsonObj.getUserId();
+ String isAAF = jsonObj.getIsAAF();
+ String password = jsonObj.getPassword();
+ String consistency = "eventual";
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+
+ if (aid == null) {
+ resultMap.put("Exception", "Please make sure Aid is present");
+ return resultMap;
+ }
+
+ if (appName == null && userId == null && password == null && isAAF == null) {
+ resultMap.put("Exception",
+ "No parameters found to update. Please update atleast one parameter.");
+ return resultMap;
+ }
+
+ StringBuilder preCql = new StringBuilder("UPDATE admin.keyspace_master SET ");
+ if (appName != null)
+ preCql.append(" application_name = ?,");
+ if (userId != null)
+ preCql.append(" username = ?,");
+ if (password != null)
+ preCql.append(" password = ?,");
+ if (isAAF != null)
+ preCql.append(" is_aaf = ?,");
+ preCql.deleteCharAt(preCql.length() - 1);
+ preCql.append(" WHERE uuid = ?");
+ pQuery.appendQueryString(preCql.toString());
+ if (appName != null)
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
+ if (userId != null)
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), userId));
+ if (password != null)
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), password));
+ if (isAAF != null)
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.cboolean(), isAAF));
+
+
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), UUID.fromString(aid)));
+ Boolean result = MusicCore.nonKeyRelatedPut(pQuery, consistency);
+
+ if (result) {
+ resultMap.put("Success", "Your application has been updated successfully");
+ } else {
+ resultMap.put("Exception",
+ "Oops. Spomething went wrong. Please make sure Aid is correct and application is onboarded");
+ }
+
+ return resultMap;
+ }
+}
diff --git a/src/main/java/org/onap/music/rest/RestMusicBmAPI.java b/src/main/java/org/onap/music/rest/RestMusicBmAPI.java
new file mode 100644
index 00000000..90b82229
--- /dev/null
+++ b/src/main/java/org/onap/music/rest/RestMusicBmAPI.java
@@ -0,0 +1,313 @@
+/*
+ * ============LICENSE_START========================================== org.onap.music
+ * =================================================================== Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.rest;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
+import org.apache.log4j.Logger;
+import org.onap.music.datastore.jsonobjects.JsonInsert;
+import org.onap.music.datastore.jsonobjects.JsonOnboard;
+import org.onap.music.datastore.jsonobjects.JsonUpdate;
+import org.onap.music.main.CachingUtil;
+import org.onap.music.main.MusicCore;
+import org.onap.music.main.MusicUtil;
+import org.onap.music.main.ResultType;
+import org.onap.music.main.ReturnType;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.music.datastore.PreparedQueryObject;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.TableMetadata;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+
+/*
+ * These are functions created purely for benchmarking purposes. Commented out Swagger - This should
+ * be undocumented API
+ *
+ */
+@Path("/v{version: [0-9]+}/benchmarks/")
+@Api(value = "Benchmark API", hidden = true)
+public class RestMusicBmAPI {
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(RestMusicBmAPI.class);
+
+ // pure zk calls...
+
+ /**
+ *
+ * @param nodeName
+ * @throws Exception
+ */
+ @POST
+ @Path("/purezk/{name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public void pureZkCreate(@PathParam("name") String nodeName) throws Exception {
+ MusicCore.pureZkCreate("/" + nodeName);
+ }
+
+
+ /**
+ *
+ * @param insObj
+ * @param nodeName
+ * @throws Exception
+ */
+ @PUT
+ @Path("/purezk/{name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public void pureZkUpdate(JsonInsert insObj, @PathParam("name") String nodeName)
+ throws Exception {
+ logger.info("--------------Zk normal update-------------------------");
+ long start = System.currentTimeMillis();
+ MusicCore.pureZkWrite(nodeName, insObj.serialize());
+ long end = System.currentTimeMillis();
+ logger.info("Total time taken for Zk normal update:" + (end - start) + " ms");
+ }
+
+ /**
+ *
+ * @param nodeName
+ * @return
+ * @throws Exception
+ */
+ @GET
+ @Path("/purezk/{name}")
+ @Consumes(MediaType.TEXT_PLAIN)
+ public byte[] pureZkGet(@PathParam("name") String nodeName) throws Exception {
+ return MusicCore.pureZkRead(nodeName);
+ }
+
+ /**
+ *
+ * @param insObj
+ * @param lockName
+ * @param nodeName
+ * @throws Exception
+ */
+ @PUT
+ @Path("/purezk/atomic/{lockname}/{name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public void pureZkAtomicPut(JsonInsert updateObj, @PathParam("lockname") String lockname,
+ @PathParam("name") String nodeName) throws Exception {
+ long startTime = System.currentTimeMillis();
+ String operationId = UUID.randomUUID().toString();// just for debugging purposes.
+ String consistency = updateObj.getConsistencyInfo().get("type");
+
+ logger.info("--------------Zookeeper " + consistency + " update-" + operationId
+ + "-------------------------");
+
+ byte[] data = updateObj.serialize();
+ long jsonParseCompletionTime = System.currentTimeMillis();
+
+ String lockId = MusicCore.createLockReference(lockname);
+
+ long lockCreationTime = System.currentTimeMillis();
+
+ long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
+ ReturnType lockAcqResult = MusicCore.acquireLockWithLease(lockname, lockId, leasePeriod);
+ long lockAcqTime = System.currentTimeMillis();
+ long zkPutTime = 0, lockReleaseTime = 0;
+
+ if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
+ logger.info("acquired lock with id " + lockId);
+ MusicCore.pureZkWrite(lockname, data);
+ zkPutTime = System.currentTimeMillis();
+ boolean voluntaryRelease = true;
+ if (consistency.equals("atomic"))
+ MusicCore.releaseLock(lockId, voluntaryRelease);
+ else if (consistency.equals("atomic_delete_lock"))
+ MusicCore.deleteLock(lockname);
+ lockReleaseTime = System.currentTimeMillis();
+ } else {
+ MusicCore.destroyLockRef(lockId);
+ }
+
+ long actualUpdateCompletionTime = System.currentTimeMillis();
+
+
+ long endTime = System.currentTimeMillis();
+
+ String lockingInfo = "|lock creation time:" + (lockCreationTime - jsonParseCompletionTime)
+ + "|lock accquire time:" + (lockAcqTime - lockCreationTime)
+ + "|zk put time:" + (zkPutTime - lockAcqTime);
+
+ if (consistency.equals("atomic"))
+ lockingInfo = lockingInfo + "|lock release time:" + (lockReleaseTime - zkPutTime) + "|";
+ else if (consistency.equals("atomic_delete_lock"))
+ lockingInfo = lockingInfo + "|lock delete time:" + (lockReleaseTime - zkPutTime) + "|";
+
+ String timingString = "Time taken in ms for Zookeeper " + consistency + " update-"
+ + operationId + ":" + "|total operation time:" + (endTime - startTime)
+ + "|json parsing time:" + (jsonParseCompletionTime - startTime)
+ + "|update time:" + (actualUpdateCompletionTime - jsonParseCompletionTime)
+ + lockingInfo;
+
+ logger.info(timingString);
+ }
+
+ /**
+ *
+ * @param insObj
+ * @param lockName
+ * @param nodeName
+ * @throws Exception
+ */
+ @GET
+ @Path("/purezk/atomic/{lockname}/{name}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ public void pureZkAtomicGet(JsonInsert insObj, @PathParam("lockname") String lockName,
+ @PathParam("name") String nodeName) throws Exception {
+ logger.info("--------------Zk atomic read-------------------------");
+ long start = System.currentTimeMillis();
+ String lockId = MusicCore.createLockReference(lockName);
+ long leasePeriod = MusicUtil.getDefaultLockLeasePeriod();
+ ReturnType lockAcqResult = MusicCore.acquireLockWithLease(lockName, lockId, leasePeriod);
+ if (lockAcqResult.getResult().equals(ResultType.SUCCESS)) {
+ logger.info("acquired lock with id " + lockId);
+ MusicCore.pureZkRead(nodeName);
+ boolean voluntaryRelease = true;
+ MusicCore.releaseLock(lockId, voluntaryRelease);
+ } else {
+ MusicCore.destroyLockRef(lockId);
+ }
+
+ long end = System.currentTimeMillis();
+ logger.info("Total time taken for Zk atomic read:" + (end - start) + " ms");
+ }
+
+ /**
+ *
+ * doing an update directly to cassa but through the rest api
+ *
+ * @param insObj
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ * @throws Exception
+ */
+ @PUT
+ @Path("/cassa/keyspaces/{keyspace}/tables/{tablename}/rows")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public boolean updateTableCassa(JsonInsert insObj, @PathParam("keyspace") String keyspace,
+ @PathParam("tablename") String tablename, @Context UriInfo info)
+ throws Exception {
+ long startTime = System.currentTimeMillis();
+ String operationId = UUID.randomUUID().toString();// just for debugging purposes.
+ String consistency = insObj.getConsistencyInfo().get("type");
+ logger.info("--------------Cassandra " + consistency + " update-" + operationId
+ + "-------------------------");
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ Map<String, Object> valuesMap = insObj.getValues();
+ TableMetadata tableInfo = MusicCore.returnColumnMetadata(keyspace, tablename);
+ String vectorTs = "'" + Thread.currentThread().getId() + System.currentTimeMillis() + "'";
+ String fieldValueString = "vector_ts= ? ,";
+ queryObject.addValue(vectorTs);
+
+ int counter = 0;
+ for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
+ Object valueObj = entry.getValue();
+ DataType colType = tableInfo.getColumn(entry.getKey()).getType();
+ Object valueString = MusicUtil.convertToActualDataType(colType, valueObj);
+ fieldValueString = fieldValueString + entry.getKey() + "= ?";
+ queryObject.addValue(valueString);
+ if (counter != valuesMap.size() - 1)
+ fieldValueString = fieldValueString + ",";
+ counter = counter + 1;
+ }
+
+ // get the row specifier
+ String rowSpec = "";
+ counter = 0;
+ queryObject.appendQueryString("UPDATE " + keyspace + "." + tablename + " ");
+ MultivaluedMap<String, String> rowParams = info.getQueryParameters();
+ String primaryKey = "";
+ for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
+ String keyName = entry.getKey();
+ List<String> valueList = entry.getValue();
+ String indValue = valueList.get(0);
+ DataType colType = tableInfo.getColumn(entry.getKey()).getType();
+ Object formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
+ primaryKey = primaryKey + indValue;
+ rowSpec = rowSpec + keyName + "= ? ";
+ queryObject.addValue(formattedValue);
+ if (counter != rowParams.size() - 1)
+ rowSpec = rowSpec + " AND ";
+ counter = counter + 1;
+ }
+
+
+ String ttl = insObj.getTtl();
+ String timestamp = insObj.getTimestamp();
+
+ if ((ttl != null) && (timestamp != null)) {
+
+ logger.info("both there");
+ queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
+ queryObject.addValue(Integer.parseInt(ttl));
+ queryObject.addValue(Long.parseLong(timestamp));
+ }
+
+ if ((ttl != null) && (timestamp == null)) {
+ logger.info("ONLY TTL there");
+ queryObject.appendQueryString(" USING TTL ?");
+ queryObject.addValue(Integer.parseInt(ttl));
+ }
+
+ if ((ttl == null) && (timestamp != null)) {
+ logger.info("ONLY timestamp there");
+ queryObject.appendQueryString(" USING TIMESTAMP ?");
+ queryObject.addValue(Long.parseLong(timestamp));
+ }
+ queryObject.appendQueryString(" SET " + fieldValueString + " WHERE " + rowSpec + ";");
+
+ long jsonParseCompletionTime = System.currentTimeMillis();
+
+ boolean operationResult = true;
+ MusicCore.getDSHandle().executePut(queryObject, insObj.getConsistencyInfo().get("type"));
+
+ long actualUpdateCompletionTime = System.currentTimeMillis();
+
+ long endTime = System.currentTimeMillis();
+
+ String timingString = "Time taken in ms for Cassandra " + consistency + " update-"
+ + operationId + ":" + "|total operation time:" + (endTime - startTime)
+ + "|json parsing time:" + (jsonParseCompletionTime - startTime)
+ + "|update time:" + (actualUpdateCompletionTime - jsonParseCompletionTime)
+ + "|";
+ logger.info(timingString);
+
+ return operationResult;
+ }
+
+}
diff --git a/src/main/java/org/onap/music/rest/RestMusicDataAPI.java b/src/main/java/org/onap/music/rest/RestMusicDataAPI.java
new file mode 100755
index 00000000..ba0f1a3b
--- /dev/null
+++ b/src/main/java/org/onap/music/rest/RestMusicDataAPI.java
@@ -0,0 +1,1088 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.rest;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+// import java.util.logging.Level;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.music.datastore.PreparedQueryObject;
+import org.onap.music.datastore.jsonobjects.JsonDelete;
+import org.onap.music.datastore.jsonobjects.JsonInsert;
+import org.onap.music.datastore.jsonobjects.JsonKeySpace;
+import org.onap.music.response.jsonobjects.JsonResponse;
+import org.onap.music.datastore.jsonobjects.JsonTable;
+import org.onap.music.datastore.jsonobjects.JsonUpdate;
+import org.onap.music.main.CachingUtil;
+import org.onap.music.main.MusicCore;
+import org.onap.music.main.MusicUtil;
+import org.onap.music.main.ResultType;
+import org.onap.music.main.ReturnType;
+import org.onap.music.main.MusicCore.Condition;
+import com.datastax.driver.core.DataType;
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.TableMetadata;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+
+@Path("/v{version: [0-9]+}/keyspaces")
+@Api(value = "Data Api")
+public class RestMusicDataAPI {
+ /*
+ * Header values for Versioning X-minorVersion *** - Used to request or communicate a MINOR
+ * version back from the client to the server, and from the server back to the client - This
+ * will be the MINOR version requested by the client, or the MINOR version of the last MAJOR
+ * version (if not specified by the client on the request) - Contains a single position value
+ * (e.g. if the full version is 1.24.5, X-minorVersion = "24") - Is optional for the client on
+ * request; however, this header should be provided if the client needs to take advantage of
+ * MINOR incremented version functionality - Is mandatory for the server on response
+ *
+ *** X-patchVersion *** - Used only to communicate a PATCH version in a response for
+ * troubleshooting purposes only, and will not be provided by the client on request - This will
+ * be the latest PATCH version of the MINOR requested by the client, or the latest PATCH version
+ * of the MAJOR (if not specified by the client on the request) - Contains a single position
+ * value (e.g. if the full version is 1.24.5, X-patchVersion = "5") - Is mandatory for the
+ * server on response
+ *
+ *** X-latestVersion *** - Used only to communicate an API's latest version - Is mandatory for the
+ * server on response, and shall include the entire version of the API (e.g. if the full version
+ * is 1.24.5, X-latestVersion = "1.24.5") - Used in the response to inform clients that they are
+ * not using the latest version of the API
+ *
+ */
+
+
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(RestMusicDataAPI.class);
+ private static String xLatestVersion = "X-latestVersion";
+
+ private class RowIdentifier {
+ public String primarKeyValue;
+ public StringBuilder rowIdString;
+ public PreparedQueryObject queryObject;// the string with all the row
+ // identifiers separated by AND
+
+ public RowIdentifier(String primaryKeyValue, StringBuilder rowIdString,
+ PreparedQueryObject queryObject) {
+ this.primarKeyValue = primaryKeyValue;
+ this.rowIdString = rowIdString;
+ this.queryObject = queryObject;
+ }
+ }
+
+ private String buildVersion(String major, String minor, String patch) {
+ if (minor != null) {
+ major += "." + minor;
+ if (patch != null) {
+ major += "." + patch;
+ }
+ }
+ return major;
+ }
+
+ /**
+ * Create Keyspace REST
+ *
+ * @param kspObject
+ * @param keyspaceName
+ * @return
+ * @throws Exception
+ */
+ @POST
+ @Path("/{name}")
+ @ApiOperation(value = "Create Keyspace", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> createKeySpace(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ JsonKeySpace kspObject,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("name") String keyspaceName,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = CachingUtil.verifyOnboarding(ns, userId, password);
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (!resultMap.isEmpty()) {
+ return resultMap;
+ }
+
+ resultMap = MusicCore.autheticateUser(ns, userId, password, keyspaceName, aid,
+ "createKeySpace");
+ String newAid = null;
+ if (!resultMap.isEmpty()) {
+ if (resultMap.containsKey("aid")) {
+ newAid = (String) resultMap.get("aid");
+ } else
+ return resultMap;
+ }
+
+ String consistency = MusicUtil.EVENTUAL;// for now this needs only eventual
+ // consistency
+
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ boolean result = false;
+ long start = System.currentTimeMillis();
+ Map<String, Object> replicationInfo = kspObject.getReplicationInfo();
+ String repString = "{" + MusicUtil.jsonMaptoSqlString(replicationInfo, ",") + "}";
+ queryObject.appendQueryString(
+ "CREATE KEYSPACE " + keyspaceName + " WITH replication = " + repString);
+ if (kspObject.getDurabilityOfWrites() != null) {
+ queryObject.appendQueryString(
+ " AND durable_writes = " + kspObject.getDurabilityOfWrites());
+ }
+
+ queryObject.appendQueryString(";");
+ long end = System.currentTimeMillis();
+ logger.info("Time taken for setting up query in create keyspace:" + (end - start));
+
+ try {
+ result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
+ logger.debug("resulta = " + result);
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+
+ }
+ logger.debug("result = " + result);
+ if (!result) {
+ resultMap.put("Status", String.valueOf(result));
+ resultMap.put("Exception", "Keyspace already exists. Please contact admin.");
+ if (resultMap.get("uuid").equals("new")) {
+ queryObject = new PreparedQueryObject();
+ queryObject.appendQueryString(
+ "DELETE FROM admin.keyspace_master where uuid = " + newAid);
+ queryObject.appendQueryString(";");
+ result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
+ resultMap.remove("aid");
+ resultMap.remove("uuid");
+ return resultMap;
+
+ } else {
+ queryObject = new PreparedQueryObject();
+ queryObject.appendQueryString(
+ "UPDATE admin.keyspace_master SET keyspace_name=?,password=?,is_api=null where uuid = ?;");
+ queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(),
+ MusicUtil.DEFAULTKEYSPACENAME));
+ queryObject.addValue(MusicUtil.convertToActualDataType(DataType.text(), null));
+ queryObject.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), newAid));
+ result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
+ resultMap.remove("aid");
+ resultMap.remove("uuid");
+ return resultMap;
+ }
+
+ }
+ try {
+ queryObject = new PreparedQueryObject();
+ queryObject.appendQueryString("CREATE ROLE IF NOT EXISTS '" + userId
+ + "' WITH PASSWORD = '" + password + "' AND LOGIN = true;");
+ result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
+ if (result) {
+ queryObject = new PreparedQueryObject();
+ queryObject.appendQueryString("GRANT ALL PERMISSIONS on KEYSPACE " + keyspaceName
+ + " to " + userId);
+ queryObject.appendQueryString(";");
+ result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
+ } else {
+ resultMap.remove("uuid");
+ resultMap.put("Exception", "Exception while creating user.");
+ return resultMap;
+ }
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ }
+ resultMap.remove("uuid");
+ if (CachingUtil.isAAFApplication(ns))
+ resultMap.remove("aid");
+ resultMap.put("Status", String.valueOf(result));
+ return resultMap;
+
+ }
+
+ /**
+ *
+ * @param kspObject
+ * @param keyspaceName
+ * @return
+ * @throws Exception
+ */
+ @DELETE
+ @Path("/{name}")
+ @ApiOperation(value = "Delete Keyspace", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> dropKeySpace(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ JsonKeySpace kspObject,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("name") String keyspaceName,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = MusicCore.autheticateUser(ns, userId, password,
+ keyspaceName, aid, "dropKeySpace");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty()) {
+ return resultMap;
+ }
+
+ String consistency = MusicUtil.EVENTUAL;// for now this needs only eventual
+ // consistency
+ String appName = CachingUtil.getAppName(keyspaceName);
+ String uuid = CachingUtil.getUuidFromMusicCache(keyspaceName);
+ PreparedQueryObject pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "select count(*) as count from admin.keyspace_master where application_name=? allow filtering;");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), appName));
+ Row row = MusicCore.get(pQuery).one();
+ long count = row.getLong(0);
+
+ if (count == 0) {
+ resultMap.put("Exception", "Keyspace not found. Please make sure keyspace exists.");
+ return resultMap;
+ } else if (count == 1) {
+ pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString(
+ "UPDATE admin.keyspace_master SET keyspace_name=?,password=?,is_api=null where uuid = ?;");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(),
+ MusicUtil.DEFAULTKEYSPACENAME));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.text(), null));
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
+ MusicCore.nonKeyRelatedPut(pQuery, consistency);
+ } else {
+ pQuery = new PreparedQueryObject();
+ pQuery.appendQueryString("delete from admin.keyspace_master where uuid = ?");
+ pQuery.addValue(MusicUtil.convertToActualDataType(DataType.uuid(), uuid));
+ MusicCore.nonKeyRelatedPut(pQuery, consistency);
+ }
+
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ queryObject.appendQueryString("DROP KEYSPACE " + keyspaceName + ";");
+ return new JsonResponse(MusicCore.nonKeyRelatedPut(queryObject, consistency), "", "")
+ .toMap();
+ }
+
+ /**
+ *
+ * @param tableObj
+ * @param keyspace
+ * @param tablename
+ * @return
+ * @throws Exception
+ */
+ @POST
+ @Path("/{keyspace}/tables/{tablename}")
+ @ApiOperation(value = "Create Table", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> createTable(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ JsonTable tableObj,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value = "Table Name",
+ required = true) @PathParam("tablename") String tablename,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
+ aid, "createTable");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty()) {
+ return resultMap;
+ }
+ String consistency = MusicUtil.EVENTUAL;
+ // for now this needs only eventual consistency
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ boolean result = false;
+ // first read the information about the table fields
+ Map<String, String> fields = tableObj.getFields();
+ StringBuilder fieldsString = new StringBuilder("(vector_ts text,");
+ int counter = 0;
+ String primaryKey;
+ for (Map.Entry<String, String> entry : fields.entrySet()) {
+ fieldsString.append("" + entry.getKey() + " " + entry.getValue() + "");
+ if (entry.getKey().equals("PRIMARY KEY")) {
+ primaryKey = entry.getValue().substring(entry.getValue().indexOf('(') + 1);
+ primaryKey = primaryKey.substring(0, primaryKey.indexOf(')'));
+ }
+ if (counter == fields.size() - 1)
+ fieldsString.append(")");
+ else
+ fieldsString.append(",");
+ counter = counter + 1;
+ }
+ // information about the name-value style properties
+ Map<String, Object> propertiesMap = tableObj.getProperties();
+ StringBuilder propertiesString = new StringBuilder();
+ if (propertiesMap != null) {
+ counter = 0;
+ for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) {
+ Object ot = entry.getValue();
+ String value = ot + "";
+ if (ot instanceof String) {
+ value = "'" + value + "'";
+ } else if (ot instanceof Map) {
+ Map<String, Object> otMap = (Map<String, Object>) ot;
+ value = "{" + MusicUtil.jsonMaptoSqlString(otMap, ",") + "}";
+ }
+
+ propertiesString.append(entry.getKey() + "=" + value + "");
+ if (counter != propertiesMap.size() - 1)
+ propertiesString.append(" AND ");
+
+ counter = counter + 1;
+ }
+ }
+
+ queryObject.appendQueryString("CREATE TABLE IF NOT EXISTS " + keyspace + "." + tablename
+ + " " + fieldsString);
+
+ if (propertiesMap != null)
+ queryObject.appendQueryString(" WITH " + propertiesString);
+
+ queryObject.appendQueryString(";");
+ result = MusicCore.nonKeyRelatedPut(queryObject, consistency);
+
+ return new JsonResponse(result, "", "").toMap();
+ }
+
+ /**
+ *
+ * @param keyspace
+ * @param tablename
+ * @param fieldName
+ * @param info
+ * @throws Exception
+ */
+ @POST
+ @Path("/{keyspace}/tables/{tablename}/index/{field}")
+ @ApiOperation(value = "Create Index", response = String.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> createIndex(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value = "Table Name",
+ required = true) @PathParam("tablename") String tablename,
+ @ApiParam(value = "Field Name",
+ required = true) @PathParam("field") String fieldName,
+ @Context UriInfo info, @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
+ aid, "createIndex");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty())
+ return resultMap;
+ MultivaluedMap<String, String> rowParams = info.getQueryParameters();
+ String indexName = "";
+ if (rowParams.getFirst("index_name") != null)
+ indexName = rowParams.getFirst("index_name");
+ PreparedQueryObject query = new PreparedQueryObject();
+ query.appendQueryString("Create index " + indexName + " if not exists on " + keyspace + "."
+ + tablename + " (" + fieldName + ");");
+ return new JsonResponse(MusicCore.nonKeyRelatedPut(query, "eventual"), "", "").toMap();
+
+ }
+
+ /**
+ *
+ * @param insObj
+ * @param keyspace
+ * @param tablename
+ * @return
+ * @throws Exception
+ */
+ @POST
+ @Path("/{keyspace}/tables/{tablename}/rows")
+ @ApiOperation(value = "Insert Into Table", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> insertIntoTable(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ JsonInsert insObj,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value = "Table Name",
+ required = true) @PathParam("tablename") String tablename,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
+ aid, "insertIntoTable");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty()) {
+ return resultMap;
+ }
+ ReturnType result = null;
+ Map<String, Object> valuesMap = insObj.getValues();
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ TableMetadata tableInfo = MusicCore.returnColumnMetadata(keyspace, tablename);
+ String primaryKeyName = tableInfo.getPrimaryKey().get(0).getName();
+ StringBuilder fieldsString = new StringBuilder("(vector_ts,");
+ String vectorTs =
+ String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
+ StringBuilder valueString = new StringBuilder("(" + "?" + ",");
+ queryObject.addValue(vectorTs);
+ int counter = 0;
+ String primaryKey = "";
+
+ for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
+ fieldsString.append("" + entry.getKey());
+ Object valueObj = entry.getValue();
+ if (primaryKeyName.equals(entry.getKey())) {
+ primaryKey = entry.getValue() + "";
+ primaryKey = primaryKey.replace("'", "''");
+ }
+
+ DataType colType = tableInfo.getColumn(entry.getKey()).getType();
+
+ Object formattedValue = MusicUtil.convertToActualDataType(colType, valueObj);
+ valueString.append("?");
+ queryObject.addValue(formattedValue);
+
+ if (counter == valuesMap.size() - 1) {
+ fieldsString.append(")");
+ valueString.append(")");
+ } else {
+ fieldsString.append(",");
+ valueString.append(",");
+ }
+ counter = counter + 1;
+ }
+
+ queryObject.appendQueryString("INSERT INTO " + keyspace + "." + tablename + " "
+ + fieldsString + " VALUES " + valueString);
+
+ String ttl = insObj.getTtl();
+ String timestamp = insObj.getTimestamp();
+
+ if ((ttl != null) && (timestamp != null)) {
+ logger.info("both there");
+ queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
+ queryObject.addValue(Integer.parseInt(ttl));
+ queryObject.addValue(Long.parseLong(timestamp));
+ }
+
+ if ((ttl != null) && (timestamp == null)) {
+ logger.info("ONLY TTL there");
+ queryObject.appendQueryString(" USING TTL ?");
+ queryObject.addValue(Integer.parseInt(ttl));
+ }
+
+ if ((ttl == null) && (timestamp != null)) {
+ logger.info("ONLY timestamp there");
+ queryObject.appendQueryString(" USING TIMESTAMP ?");
+ queryObject.addValue(Long.parseLong(timestamp));
+ }
+
+ queryObject.appendQueryString(";");
+
+ String consistency = insObj.getConsistencyInfo().get("type");
+ try {
+ if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL)) {
+ result = MusicCore.eventualPut(queryObject);
+ } else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
+ String lockId = insObj.getConsistencyInfo().get("lockId");
+ result = MusicCore.criticalPut(keyspace, tablename, primaryKey, queryObject, lockId,
+ null);
+ } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
+ result = MusicCore.atomicPut(keyspace, tablename, primaryKey, queryObject, null);
+
+ }
+ return (result != null) ? result.toMap()
+ : new ReturnType(ResultType.FAILURE,
+ "Null result - Please Contact admin").toMap();
+ } catch (Exception ex) {
+ logger.error(ex.getMessage());
+ return new ReturnType(ResultType.FAILURE, ex.getMessage()).toMap();
+ }
+ }
+
+ /**
+ *
+ * @param insObj
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ * @throws Exception
+ */
+ @PUT
+ @Path("/{keyspace}/tables/{tablename}/rows")
+ @ApiOperation(value = "Update Table", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> updateTable(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ JsonUpdate updateObj,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value = "Table Name",
+ required = true) @PathParam("tablename") String tablename,
+ @Context UriInfo info, @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
+ aid, "updateTable");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty()) {
+ return resultMap;
+ }
+ long startTime = System.currentTimeMillis();
+ String operationId = UUID.randomUUID().toString();// just for infoging
+ // purposes.
+ String consistency = updateObj.getConsistencyInfo().get("type");
+ logger.info("--------------Music " + consistency + " update-" + operationId
+ + "-------------------------");
+ // obtain the field value pairs of the update
+
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ Map<String, Object> valuesMap = updateObj.getValues();
+
+ TableMetadata tableInfo = MusicCore.returnColumnMetadata(keyspace, tablename);
+ String vectorTs =
+ String.valueOf(Thread.currentThread().getId() + System.currentTimeMillis());
+ StringBuilder fieldValueString = new StringBuilder("vector_ts=?,");
+ queryObject.addValue(vectorTs);
+ int counter = 0;
+ for (Map.Entry<String, Object> entry : valuesMap.entrySet()) {
+ Object valueObj = entry.getValue();
+ DataType colType = tableInfo.getColumn(entry.getKey()).getType();
+ Object valueString = MusicUtil.convertToActualDataType(colType, valueObj);
+ fieldValueString.append(entry.getKey() + "= ?");
+ queryObject.addValue(valueString);
+ if (counter != valuesMap.size() - 1)
+ fieldValueString.append(",");
+ counter = counter + 1;
+ }
+ String ttl = updateObj.getTtl();
+ String timestamp = updateObj.getTimestamp();
+
+ queryObject.appendQueryString("UPDATE " + keyspace + "." + tablename + " ");
+ if ((ttl != null) && (timestamp != null)) {
+
+ logger.info("both there");
+ queryObject.appendQueryString(" USING TTL ? AND TIMESTAMP ?");
+ queryObject.addValue(Integer.parseInt(ttl));
+ queryObject.addValue(Long.parseLong(timestamp));
+ }
+
+ if ((ttl != null) && (timestamp == null)) {
+ logger.info("ONLY TTL there");
+ queryObject.appendQueryString(" USING TTL ?");
+ queryObject.addValue(Integer.parseInt(ttl));
+ }
+
+ if ((ttl == null) && (timestamp != null)) {
+ logger.info("ONLY timestamp there");
+ queryObject.appendQueryString(" USING TIMESTAMP ?");
+ queryObject.addValue(Long.parseLong(timestamp));
+ }
+ // get the row specifier
+ RowIdentifier rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(),
+ queryObject);
+
+ queryObject.appendQueryString(
+ " SET " + fieldValueString + " WHERE " + rowId.rowIdString + ";");
+
+ // get the conditional, if any
+ Condition conditionInfo;
+ if (updateObj.getConditions() == null)
+ conditionInfo = null;
+ else {// to avoid parsing repeatedly, just send the select query to
+ // obtain row
+ String selectQuery = "SELECT * FROM " + keyspace + "." + tablename + " WHERE "
+ + rowId.rowIdString + ";";
+ conditionInfo = new MusicCore.Condition(updateObj.getConditions(), selectQuery);
+ }
+
+ ReturnType operationResult = null;
+ long jsonParseCompletionTime = System.currentTimeMillis();
+
+ if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
+ operationResult = MusicCore.eventualPut(queryObject);
+ else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
+ String lockId = updateObj.getConsistencyInfo().get("lockId");
+ operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
+ queryObject, lockId, conditionInfo);
+ }
+ else if (consistency.equalsIgnoreCase("atomic_delete_lock")) {
+ // this function is mainly for the benchmarks
+ operationResult = MusicCore.atomicPutWithDeleteLock(keyspace, tablename,
+ rowId.primarKeyValue, queryObject, conditionInfo);
+ } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
+ operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
+ queryObject, conditionInfo);
+ }
+ long actualUpdateCompletionTime = System.currentTimeMillis();
+
+ long endTime = System.currentTimeMillis();
+ String timingString = "Time taken in ms for Music " + consistency + " update-" + operationId
+ + ":" + "|total operation time:" + (endTime - startTime)
+ + "|json parsing time:" + (jsonParseCompletionTime - startTime)
+ + "|update time:" + (actualUpdateCompletionTime - jsonParseCompletionTime)
+ + "|";
+
+ if (operationResult != null && operationResult.getTimingInfo() != null) {
+ String lockManagementTime = operationResult.getTimingInfo();
+ timingString = timingString + lockManagementTime;
+ }
+ logger.info(timingString);
+ return (operationResult != null) ? operationResult.toMap()
+ : new ReturnType(ResultType.FAILURE, "Null result - Please Contact admin")
+ .toMap();
+ }
+
+ /**
+ *
+ * @param delObj
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ * @throws Exception
+ */
+ @DELETE
+ @Path("/{keyspace}/tables/{tablename}/rows")
+ @ApiOperation(value = "Delete From table", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, Object> deleteFromTable(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ JsonDelete delObj,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value = "Table Name",
+ required = true) @PathParam("tablename") String tablename,
+ @Context UriInfo info, @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
+ aid, "deleteFromTable");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty()) {
+ return resultMap;
+ }
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ StringBuilder columnString = new StringBuilder();
+
+ int counter = 0;
+ ArrayList<String> columnList = delObj.getColumns();
+ if (columnList != null) {
+ for (String column : columnList) {
+ columnString.append(column);
+ if (counter != columnList.size() - 1)
+ columnString.append(",");
+ counter = counter + 1;
+ }
+ }
+
+ // get the row specifier
+ RowIdentifier rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(),
+ queryObject);
+ String rowSpec = rowId.rowIdString.toString();
+
+ if ((columnList != null) && (!rowSpec.isEmpty())) {
+ queryObject.appendQueryString("DELETE " + columnString + " FROM " + keyspace + "."
+ + tablename + " WHERE " + rowSpec + ";");
+ }
+
+ if ((columnList == null) && (!rowSpec.isEmpty())) {
+ queryObject.appendQueryString("DELETE FROM " + keyspace + "." + tablename + " WHERE "
+ + rowSpec + ";");
+ }
+
+ if ((columnList != null) && (rowSpec.isEmpty())) {
+ queryObject.appendQueryString(
+ "DELETE " + columnString + " FROM " + keyspace + "." + rowSpec + ";");
+ }
+
+ // get the conditional, if any
+ Condition conditionInfo;
+ if (delObj.getConditions() == null)
+ conditionInfo = null;
+ else {// to avoid parsing repeatedly, just send the select query to
+ // obtain row
+ String selectQuery = "SELECT * FROM " + keyspace + "." + tablename + " WHERE "
+ + rowId.rowIdString + ";";
+ conditionInfo = new MusicCore.Condition(delObj.getConditions(), selectQuery);
+ }
+
+ String consistency = delObj.getConsistencyInfo().get("type");
+
+ ReturnType operationResult = null;
+
+ if (consistency.equalsIgnoreCase(MusicUtil.EVENTUAL))
+ operationResult = MusicCore.eventualPut(queryObject);
+ else if (consistency.equalsIgnoreCase(MusicUtil.CRITICAL)) {
+ String lockId = delObj.getConsistencyInfo().get("lockId");
+ operationResult = MusicCore.criticalPut(keyspace, tablename, rowId.primarKeyValue,
+ queryObject, lockId, conditionInfo);
+ } else if (consistency.equalsIgnoreCase(MusicUtil.ATOMIC)) {
+ operationResult = MusicCore.atomicPut(keyspace, tablename, rowId.primarKeyValue,
+ queryObject, conditionInfo);
+ }
+ try {
+ return operationResult.toMap();
+ } catch (NullPointerException e) {
+ return new ReturnType(ResultType.FAILURE, e.getMessage()).toMap();
+ }
+ }
+
+ /**
+ *
+ * @param tabObj
+ * @param keyspace
+ * @param tablename
+ * @throws Exception
+ */
+ @DELETE
+ @Path("/{keyspace}/tables/{tablename}")
+ @ApiOperation(value = "Drop Table", response = String.class)
+
+ public Map<String, Object> dropTable(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ JsonTable tabObj,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value = "Table Name",
+ required = true) @PathParam("tablename") String tablename,
+ @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap =
+ MusicCore.autheticateUser(ns, userId, password, keyspace, aid, "dropTable");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty()) {
+ return resultMap;
+ }
+ String consistency = "eventual";// for now this needs only eventual
+ // consistency
+ PreparedQueryObject query = new PreparedQueryObject();
+ query.appendQueryString("DROP TABLE IF EXISTS " + keyspace + "." + tablename + ";");
+ return new JsonResponse(MusicCore.nonKeyRelatedPut(query, consistency), "", "").toMap();
+ }
+
+ /**
+ *
+ * @param selObj
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ */
+ @PUT
+ @Path("/{keyspace}/tables/{tablename}/rows/criticalget")
+ @ApiOperation(value = "Select Critical", response = Map.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, HashMap<String, Object>> selectCritical(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ JsonInsert selObj,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value = "Table Name",
+ required = true) @PathParam("tablename") String tablename,
+ @Context UriInfo info, @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap = MusicCore.autheticateUser(ns, userId, password, keyspace,
+ aid, "selectCritical");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty()) {
+ logger.error("Error while authentication... ");
+ HashMap<String, Object> tempMap = new HashMap<>();
+ tempMap.putAll(resultMap);
+ Map<String, HashMap<String, Object>> results = new HashMap<>();
+ results.put("Result", tempMap);
+ return results;
+ }
+ String lockId = selObj.getConsistencyInfo().get("lockId");
+
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ StringBuilder rowSpec = new StringBuilder();
+
+ RowIdentifier rowId = getRowIdentifier(keyspace, tablename, info.getQueryParameters(),
+ queryObject);
+
+ queryObject.appendQueryString(
+ "SELECT * FROM " + keyspace + "." + tablename + " WHERE " + rowSpec + ";");
+
+ ResultSet results = null;
+
+ String consistency = selObj.getConsistencyInfo().get("type");
+
+ if (consistency.equalsIgnoreCase("critical")) {
+ results = MusicCore.criticalGet(keyspace, tablename, rowId.primarKeyValue, queryObject,
+ lockId);
+ } else if (consistency.equalsIgnoreCase("atomic")) {
+ results = MusicCore.atomicGet(keyspace, tablename, rowId.primarKeyValue, queryObject);
+ }
+
+ return MusicCore.marshallResults(results);
+ }
+
+ /**
+ *
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ * @throws Exception
+ */
+ @GET
+ @Path("/{keyspace}/tables/{tablename}/rows")
+ @ApiOperation(value = "Select All or Select Specivic", response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, HashMap<String, Object>> select(
+ @ApiParam(value = "Major Version",
+ required = true) @PathParam("version") String version,
+ @ApiParam(value = "Minor Version",
+ required = false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value = "Patch Version",
+ required = false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value = "AID", required = true) @HeaderParam("aid") String aid,
+ @ApiParam(value = "Application namespace",
+ required = true) @HeaderParam("ns") String ns,
+ @ApiParam(value = "userId",
+ required = true) @HeaderParam("userId") String userId,
+ @ApiParam(value = "Password",
+ required = true) @HeaderParam("password") String password,
+ @ApiParam(value = "Keyspace Name",
+ required = true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value = "Table Name",
+ required = true) @PathParam("tablename") String tablename,
+ @Context UriInfo info, @Context HttpServletResponse response) throws Exception {
+ Map<String, Object> resultMap =
+ MusicCore.autheticateUser(ns, userId, password, keyspace, aid, "select");
+ response.addHeader(xLatestVersion, MusicUtil.getVersion());
+ if (resultMap.containsKey("aid"))
+ resultMap.remove("aid");
+ if (!resultMap.isEmpty()) {
+ logger.error("Error while authentication... ");
+ HashMap<String, Object> tempMap = new HashMap<>();
+ tempMap.putAll(resultMap);
+ Map<String, HashMap<String, Object>> results = new HashMap<>();
+ results.put("Result", tempMap);
+ return results;
+ }
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+
+ if (info.getQueryParameters().isEmpty())// select all
+ queryObject.appendQueryString("SELECT * FROM " + keyspace + "." + tablename + ";");
+ else {
+ int limit = -1; // do not limit the number of results
+ queryObject = selectSpecificQuery(version, minorVersion, patchVersion, aid, ns, userId,
+ password, keyspace, tablename, info, limit);
+ }
+ ResultSet results = MusicCore.get(queryObject);
+ return MusicCore.marshallResults(results);
+ }
+
+ /**
+ *
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @param limit
+ * @return
+ * @throws Exception
+ */
+ public PreparedQueryObject selectSpecificQuery(String version, String minorVersion,
+ String patchVersion, String aid, String ns, String userId, String password,
+ String keyspace, String tablename, UriInfo info, int limit) {
+
+ PreparedQueryObject queryObject = new PreparedQueryObject();
+ StringBuilder rowIdString = getRowIdentifier(keyspace, tablename, info.getQueryParameters(),
+ queryObject).rowIdString;
+
+ queryObject.appendQueryString(
+ "SELECT * FROM " + keyspace + "." + tablename + " WHERE " + rowIdString);
+
+ if (limit != -1) {
+ queryObject.appendQueryString(" LIMIT " + limit);
+ }
+
+ queryObject.appendQueryString(";");
+ return queryObject;
+
+ }
+
+ /**
+ *
+ * @param keyspace
+ * @param tablename
+ * @param rowParams
+ * @param queryObject
+ * @return
+ * @throws Exception
+ */
+ private RowIdentifier getRowIdentifier(String keyspace, String tablename,
+ MultivaluedMap<String, String> rowParams, PreparedQueryObject queryObject) {
+ StringBuilder rowSpec = new StringBuilder();
+ int counter = 0;
+ TableMetadata tableInfo = MusicCore.returnColumnMetadata(keyspace, tablename);
+ StringBuilder primaryKey = new StringBuilder();
+ for (MultivaluedMap.Entry<String, List<String>> entry : rowParams.entrySet()) {
+ String keyName = entry.getKey();
+ List<String> valueList = entry.getValue();
+ String indValue = valueList.get(0);
+ DataType colType = tableInfo.getColumn(entry.getKey()).getType();
+ Object formattedValue = MusicUtil.convertToActualDataType(colType, indValue);
+ primaryKey.append(indValue);
+ rowSpec.append(keyName + "= ?");
+ queryObject.addValue(formattedValue);
+ if (counter != rowParams.size() - 1)
+ rowSpec.append(" AND ");
+ counter = counter + 1;
+ }
+ return new RowIdentifier(primaryKey.toString(), rowSpec, queryObject);
+ }
+
+}
diff --git a/src/main/java/org/onap/music/rest/RestMusicLocksAPI.java b/src/main/java/org/onap/music/rest/RestMusicLocksAPI.java
new file mode 100644
index 00000000..8612b1fa
--- /dev/null
+++ b/src/main/java/org/onap/music/rest/RestMusicLocksAPI.java
@@ -0,0 +1,209 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.rest;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+
+import org.onap.music.datastore.jsonobjects.JsonLeasedLock;
+import org.onap.music.lockingservice.MusicLockState;
+import org.onap.music.main.MusicCore;
+import org.onap.music.main.MusicUtil;
+import org.onap.music.response.jsonobjects.JsonLockResponse;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+
+
+@Path("/v{version: [0-9]+}/locks/")
+@Api(value="Lock Api")
+public class RestMusicLocksAPI {
+
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(RestMusicLocksAPI.class);
+ private static String xLatestVersion = "X-latestVersion";
+ /**
+ * Puts the requesting process in the q for this lock. The corresponding
+ * node will be created in zookeeper if it did not already exist
+ *
+ * @param lockName
+ * @return
+ */
+
+ @POST
+ @Path("/create/{lockname}")
+ @ApiOperation(value = "Create Lock",
+ notes = "Puts the requesting process in the q for this lock." +
+ " The corresponding node will be created in zookeeper if it did not already exist." +
+ " Lock Name is the \"key\" of the form keyspaceName.tableName.rowId",
+ response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> createLockReference(
+ @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName,
+ @Context HttpServletResponse response){
+ response.addHeader(xLatestVersion,MusicUtil.getVersion());
+ Boolean status = true;
+ String lockId = MusicCore.createLockReference(lockName);
+ if ( lockId == null ) { status = false; }
+ return new JsonLockResponse(status.toString(),"",lockId).toMap();
+ }
+
+ /**
+ *
+ * Checks if the node is in the top of the queue and hence acquires the lock
+ *
+ * @param lockId
+ * @return
+ */
+ @GET
+ @Path("/acquire/{lockreference}")
+ @ApiOperation(value = "Aquire Lock",
+ notes = "Checks if the node is in the top of the queue and hence acquires the lock",
+ response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> accquireLock(
+ @ApiParam(value="Lock Reference",required=true) @PathParam("lockreference") String lockId,
+ @Context HttpServletResponse response){
+ response.addHeader(xLatestVersion,MusicUtil.getVersion());
+ String lockName = lockId.substring(lockId.indexOf('$')+1, lockId.lastIndexOf('$'));
+ Boolean lockStatus = MusicCore.acquireLock(lockName,lockId);
+ return new JsonLockResponse(lockStatus.toString(),"",lockId,lockStatus.toString(),"").toMap();
+ }
+
+
+
+
+ @POST
+ @Path("/acquire-with-lease/{lockreference}")
+ @ApiOperation(value = "Aquire Lock with Lease", response = Map.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> accquireLockWithLease(JsonLeasedLock lockObj,
+ @ApiParam(value="Lock Reference",required=true) @PathParam("lockreference") String lockId,
+ @Context HttpServletResponse response){
+ response.addHeader(xLatestVersion,MusicUtil.getVersion());
+ String lockName = lockId.substring(lockId.indexOf('$')+1, lockId.lastIndexOf('$'));
+ String lockLeaseStatus = MusicCore.acquireLockWithLease(lockName, lockId, lockObj.getLeasePeriod()).toString();
+ return new JsonLockResponse(lockLeaseStatus,"",lockName,lockLeaseStatus,"",String.valueOf(lockObj.getLeasePeriod())).toMap();
+ }
+
+
+ @GET
+ @Path("/enquire/{lockname}")
+ @ApiOperation(value = "Get Lock Holder",
+ notes = "Gets the current Lock Holder",
+ response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> currentLockHolder(
+ @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName,
+ @Context HttpServletResponse response){
+ response.addHeader(xLatestVersion,MusicUtil.getVersion());
+ String who = MusicCore.whoseTurnIsIt(lockName);
+ String status = "true";
+ String error = "";
+ if ( who == null ) {
+ status = "false";
+ error = "There was a problem getting the lock holder";
+ }
+ return new JsonLockResponse(status,error,lockName,"",who).toMap();
+ }
+
+ @GET
+ @Path("/{lockname}")
+ @ApiOperation(value = "Lock State",
+ notes = "Returns current Lock State and Holder.",
+ response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> currentLockState(
+ @ApiParam(value="Lock Name",required=true) @PathParam("lockname") String lockName,
+ @Context HttpServletResponse response){
+ response.addHeader(xLatestVersion,MusicUtil.getVersion());
+ MusicLockState mls = MusicCore.getMusicLockState(lockName);
+ Map<String,Object> returnMap = null;
+ JsonLockResponse jsonResponse = new JsonLockResponse("false","",lockName);
+ if(mls == null) {
+ jsonResponse.setError("");
+ jsonResponse.setMessage("No lock object created yet..");
+ } else {
+ jsonResponse.setStatus("true");
+ jsonResponse.setLockStatus(mls.getLockStatus().toString());
+ jsonResponse.setLockHolder(mls.getLockHolder());
+ }
+ return returnMap;
+ }
+
+ /**
+ *
+ * deletes the process from the zk queue
+ *
+ * @param lockId
+ */
+ @DELETE
+ @Path("/release/{lockreference}")
+ @ApiOperation(value = "Release Lock",
+ notes = "deletes the process from the zk queue",
+ response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> unLock(@PathParam("lockreference") String lockId,
+ @Context HttpServletResponse response){
+ response.addHeader(xLatestVersion,MusicUtil.getVersion());
+ boolean voluntaryRelease = true;
+ MusicLockState mls = MusicCore.releaseLock(lockId,voluntaryRelease);
+ Map<String,Object> returnMap = null;
+ if ( mls.getLockStatus() == MusicLockState.LockStatus.UNLOCKED ) {
+ returnMap = new JsonLockResponse("Unlocked","","").toMap();
+ }
+ if ( mls.getLockStatus() == MusicLockState.LockStatus.LOCKED) {
+ returnMap = new JsonLockResponse("Locked","","").toMap();
+ }
+ return returnMap;
+ }
+
+ /**
+ *
+ * @param lockName
+ */
+ @DELETE
+ @Path("/delete/{lockname}")
+ @ApiOperation(value = "Delete Lock", response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> deleteLock(@PathParam("lockname") String lockName,
+ @Context HttpServletResponse response){
+ response.addHeader(xLatestVersion,MusicUtil.getVersion());
+ MusicCore.deleteLock(lockName);
+ return new JsonLockResponse("true","","").toMap();
+ }
+
+}
diff --git a/src/main/java/org/onap/music/rest/RestMusicQAPI.java b/src/main/java/org/onap/music/rest/RestMusicQAPI.java
new file mode 100755
index 00000000..3e92461c
--- /dev/null
+++ b/src/main/java/org/onap/music/rest/RestMusicQAPI.java
@@ -0,0 +1,257 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.rest;
+
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+
+import org.onap.music.datastore.jsonobjects.JsonDelete;
+import org.onap.music.datastore.jsonobjects.JsonInsert;
+import org.onap.music.datastore.jsonobjects.JsonTable;
+import org.onap.music.datastore.jsonobjects.JsonUpdate;
+import org.onap.music.main.MusicCore;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import org.onap.music.datastore.PreparedQueryObject;
+import com.datastax.driver.core.ResultSet;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+
+//@Path("/v{version: [0-9]+}/priorityq/")
+@Path("/priorityq/")
+@Api(value="Q Api")
+public class RestMusicQAPI {
+
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(RestMusicQAPI.class);
+
+
+ /**
+ *
+ * @param tableObj
+ * @param keyspace
+ * @param tablename
+ * @throws Exception
+ */
+
+ @POST
+ @Path("/keyspaces/{keyspace}/{qname}")
+ @ApiOperation(value = "", response = Void.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Map<String,Object> createQ(
+ @ApiParam(value="Major Version",required=true) @PathParam("version") String version,
+ @ApiParam(value="Minor Version",required=false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value="Patch Version",required=false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value="AID",required=true) @HeaderParam("aid") String aid,
+ @ApiParam(value="Application namespace",required=true) @HeaderParam("ns") String ns,
+ @ApiParam(value="userId",required=true) @HeaderParam("userId") String userId,
+ @ApiParam(value="Password",required=true) @HeaderParam("password") String password, JsonTable tableObj,
+ @ApiParam(value="Key Space",required=true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value="Table Name",required=true) @PathParam("tablename") String tablename,
+ @Context HttpServletResponse response) throws Exception{
+ return new RestMusicDataAPI().createTable(version,minorVersion,patchVersion,aid, ns, userId, password, tableObj, keyspace, tablename,response);
+ }
+
+ /**
+ *
+ * @param insObj
+ * @param keyspace
+ * @param tablename
+ * @throws Exception
+ */
+ @POST
+ @Path("/keyspaces/{keyspace}/{qname}/rows")
+ @ApiOperation(value = "", response = Void.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> insertIntoQ(
+ @ApiParam(value="Major Version",required=true) @PathParam("version") String version,
+ @ApiParam(value="Minor Version",required=false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value="Patch Version",required=false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value="AID",required=true) @HeaderParam("aid") String aid,
+ @ApiParam(value="Application namespace",required=true) @HeaderParam("ns") String ns, @ApiParam(value="userId",required=true) @HeaderParam("userId") String userId,
+ @ApiParam(value="Password",required=true) @HeaderParam("password") String password, JsonInsert insObj,
+ @ApiParam(value="Key Space",required=true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value="Table Name",required=true) @PathParam("tablename") String tablename,
+ @Context HttpServletResponse response) throws Exception{
+ return new RestMusicDataAPI().insertIntoTable(version,minorVersion,patchVersion,aid, ns, userId, password, insObj, keyspace, tablename,response);
+ }
+
+ /**
+ *
+ * @param updateObj
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ * @throws Exception
+ */
+ @PUT
+ @Path("/keyspaces/{keyspace}/{qname}/rows")
+ @ApiOperation(value = "", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> updateQ(
+ @ApiParam(value="Major Version",required=true) @PathParam("version") String version,
+ @ApiParam(value="Minor Version",required=false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value="Patch Version",required=false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value="AID",required=true) @HeaderParam("aid") String aid,
+ @ApiParam(value="Application namespace",required=true) @HeaderParam("ns") String ns, @ApiParam(value="userId",required=true) @HeaderParam("userId") String userId,
+ @ApiParam(value="Password",required=true) @HeaderParam("password") String password, JsonUpdate updateObj,
+ @ApiParam(value="Key Space",required=true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value="Table Name",required=true) @PathParam("tablename") String tablename,
+ @Context UriInfo info,
+ @Context HttpServletResponse response) throws Exception{
+ return new RestMusicDataAPI().updateTable(version,minorVersion,patchVersion,aid, ns, userId, password, updateObj, keyspace, tablename, info,response);
+ }
+
+ /**
+ *
+ * @param delObj
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ * @throws Exception
+ */
+ @DELETE
+ @Path("/keyspaces/{keyspace}/{qname}/rows")
+ @ApiOperation(value = "", response = String.class)
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> deleteFromQ(
+ @ApiParam(value="Major Version",required=true) @PathParam("version") String version,
+ @ApiParam(value="Minor Version",required=false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value="Patch Version",required=false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value="AID",required=true) @HeaderParam("aid") String aid,
+ @ApiParam(value="Application namespace",required=true) @HeaderParam("ns") String ns,
+ @ApiParam(value="userId",required=true) @HeaderParam("userId") String userId,
+ @ApiParam(value="Password",required=true) @HeaderParam("password") String password, JsonDelete delObj,
+ @ApiParam(value="Key Space",required=true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value="Table Name",required=true) @PathParam("tablename") String tablename,
+ @Context UriInfo info,
+ @Context HttpServletResponse response) throws Exception{
+ return new RestMusicDataAPI().deleteFromTable(version,minorVersion,patchVersion,aid, ns, userId, password, delObj, keyspace, tablename, info,response);
+ }
+
+ /**
+ *
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ * @throws Exception
+ */
+ @GET
+ @Path("/keyspaces/{keyspace}/{qname}/peek")
+ @ApiOperation(value = "", response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, HashMap<String, Object>> peek(
+ @ApiParam(value="Major Version",required=true) @PathParam("version") String version,
+ @ApiParam(value="Minor Version",required=false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value="Patch Version",required=false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value="AID",required=true) @HeaderParam("aid") String aid,
+ @ApiParam(value="Application namespace",required=true) @HeaderParam("ns") String ns,
+ @ApiParam(value="userId",required=true) @HeaderParam("userId") String userId,
+ @ApiParam(value="Password",required=true) @HeaderParam("password") String password,
+ @ApiParam(value="Key Space",required=true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value="Table Name",required=true) @PathParam("tablename") String tablename,
+ @Context UriInfo info) throws Exception{
+ int limit =1; //peek must return just the top row
+ PreparedQueryObject query = new RestMusicDataAPI().selectSpecificQuery(version,minorVersion,patchVersion,aid, ns, userId, password,keyspace,tablename,info,limit);
+ ResultSet results = MusicCore.get(query);
+ return MusicCore.marshallResults(results);
+
+ }
+
+ /**
+ *
+ *
+ * @param keyspace
+ * @param tablename
+ * @param info
+ * @return
+ * @throws Exception
+ */
+ @GET
+ @Path("/keyspaces/{keyspace}/{qname}/filter")
+ @ApiOperation(value = "", response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, HashMap<String, Object>> filter(
+ @ApiParam(value="Major Version",required=true) @PathParam("version") String version,
+ @ApiParam(value="Minor Version",required=false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value="Patch Version",required=false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value="AID",required=true) @HeaderParam("aid") String aid,
+ @ApiParam(value="Application namespace",required=true) @HeaderParam("ns") String ns,
+ @ApiParam(value="userId",required=true) @HeaderParam("userId") String userId,
+ @ApiParam(value="Password",required=true) @HeaderParam("password") String password,
+ @ApiParam(value="Key Space",required=true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value="Table Name",required=true) @PathParam("tablename") String tablename,
+ @Context UriInfo info) throws Exception{
+ int limit =-1;
+ PreparedQueryObject query = new RestMusicDataAPI().selectSpecificQuery(version,minorVersion,patchVersion,aid, ns, userId, password,keyspace,tablename,info,limit);
+ ResultSet results = MusicCore.get(query);
+ return MusicCore.marshallResults(results);
+ }
+
+ /**
+ *
+ * @param tabObj
+ * @param keyspace
+ * @param tablename
+ * @throws Exception
+ */
+ @DELETE
+ @ApiOperation(value = "", response = Void.class)
+ @Path("/keyspaces/{keyspace}/{qname}")
+ public Map<String,Object> dropQ(
+ @ApiParam(value="Major Version",required=true) @PathParam("version") String version,
+ @ApiParam(value="Minor Version",required=false) @HeaderParam("X-minorVersion") String minorVersion,
+ @ApiParam(value="Patch Version",required=false) @HeaderParam("X-patchVersion") String patchVersion,
+ @ApiParam(value="AID",required=true) @HeaderParam("aid") String aid,
+ @ApiParam(value="Application namespace",required=true) @HeaderParam("ns") String ns,
+ @ApiParam(value="userId",required=true) @HeaderParam("userId") String userId,
+ @ApiParam(value="Password",required=true) @HeaderParam("password") String password, JsonTable tabObj,
+ @ApiParam(value="Key Space",required=true) @PathParam("keyspace") String keyspace,
+ @ApiParam(value="Table Name",required=true) @PathParam("tablename") String tablename,
+ @Context HttpServletResponse response) throws Exception{
+ return new RestMusicDataAPI().dropTable(version,minorVersion,patchVersion,aid, ns, userId, password, tabObj, keyspace, tablename,response);
+ }
+}
diff --git a/src/main/java/org/onap/music/rest/RestMusicTestAPI.java b/src/main/java/org/onap/music/rest/RestMusicTestAPI.java
new file mode 100644
index 00000000..6b6bc101
--- /dev/null
+++ b/src/main/java/org/onap/music/rest/RestMusicTestAPI.java
@@ -0,0 +1,67 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.rest;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+
+import org.onap.music.main.MusicUtil;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+
+@Path("/v{version: [0-9]+}/test")
+@Api(value="Test Api")
+public class RestMusicTestAPI {
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(RestMusicTestAPI.class);
+
+ /**
+ * Returns a test JSON. This will confirm that REST is working.
+ * @return
+ */
+ @GET
+ @ApiOperation(value = "Get Test", response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String, HashMap<String, String>> simpleTests(
+ @Context HttpServletResponse response) {
+ response.addHeader("X-latestVersion",MusicUtil.getVersion());
+ Map<String, HashMap<String, String>> testMap = new HashMap<>();
+ for(int i=0; i < 3; i++){
+ HashMap<String, String> innerMap = new HashMap<>();
+ innerMap.put(i+"", i+1+"");
+ innerMap.put(i+1+"", i+2+"");
+ testMap.put(i+"", innerMap);
+ }
+ return testMap;
+ }
+}
diff --git a/src/main/java/org/onap/music/rest/RestMusicVersionAPI.java b/src/main/java/org/onap/music/rest/RestMusicVersionAPI.java
new file mode 100644
index 00000000..924b0289
--- /dev/null
+++ b/src/main/java/org/onap/music/rest/RestMusicVersionAPI.java
@@ -0,0 +1,61 @@
+/*
+ * ============LICENSE_START==========================================
+ * org.onap.music
+ * ===================================================================
+ * Copyright (c) 2017 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.
+ *
+ * ============LICENSE_END=============================================
+ * ====================================================================
+ */
+package org.onap.music.rest;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+
+import org.onap.music.response.jsonobjects.JsonResponse;
+import org.onap.music.main.MusicUtil;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+
+@Path("/v{version: [0-9]+}/version")
+@Api(value="Version Api")
+public class RestMusicVersionAPI {
+
+ private static EELFLogger logger = EELFManager.getInstance().getLogger(RestMusicVersionAPI.class);
+ /**
+ * Get the version of MUSIC
+ * @return
+ */
+ @GET
+ @ApiOperation(value = "Get Version", response = Map.class)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Map<String,Object> version(@Context HttpServletResponse response) {
+ logger.info("Replying to request for MUSIC version with MUSIC:" + MusicUtil.getVersion());
+ JsonResponse jResponse = new JsonResponse(true,"","MUSIC:" + MusicUtil.getVersion());
+ response.addHeader("X-latestVersion",MusicUtil.getVersion());
+ return jResponse.toMap();
+ }
+} \ No newline at end of file
diff --git a/src/main/resources/LICENSE.txt b/src/main/resources/LICENSE.txt
new file mode 100644
index 00000000..cc6cdea5
--- /dev/null
+++ b/src/main/resources/LICENSE.txt
@@ -0,0 +1,24 @@
+
+The following license applies to all files in this and sub-directories. Licenses
+are included in individual source files where appropriate, and if it differs
+from this text, it supersedes this. Any file that does not have license text
+defaults to being covered by this text; not all files support the addition of
+licenses.
+#
+# -------------------------------------------------------------------------
+# Copyright (c) 2017 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.
+#
+# -------------------------------------------------------------------------
+# \ No newline at end of file
diff --git a/src/main/resources/Resources.properties b/src/main/resources/Resources.properties
new file mode 100644
index 00000000..7ee7baae
--- /dev/null
+++ b/src/main/resources/Resources.properties
@@ -0,0 +1,49 @@
+#============LICENSE_START==========================================
+#org.onap.music
+#===================================================================
+# Copyright (c) 2017 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.
+#
+#============LICENSE_END=============================================
+#====================================================================
+#Resource key=Error Code|Message text|Resolution text |Description text
+LOADING_DEFAULT_LOG_CONFIGURATION=\
+ EELF0001I|\
+ Loading default logging configuration from system resource file "{0}"|\
+ No external logging configurations were defined or found, So verify the default logging configuration from system resource file (../logback.xml). |\
+ Loading default logging configuration from system resource file
+LOADING_LOG_CONFIGURATION=EELF0002I|\
+ Loading logging configuration from file "{0}"|\
+ Verify the correct logging configuration file is loaded. |\
+ Loading logging configuration for specific file
+LOGGING_ALREADY_INITIALIZED=\
+ EELF0003W|\
+ Logging has already been initialized, check the container logging definitions to ensure they represent your desired logging configuration.|\
+ Verify the container logging definitions to ensure they represent your desired logging configuration. |\
+ Logging has already been initialized, check the container logging definitions to ensure they represent your desired logging configuration.
+NO_LOG_CONFIGURATION=\
+ EELF0004E|\
+ No log configuration could be found or defaulted!|\
+ No external and default logging configuration file. |\
+ No log configuration could be found or defaulted!
+SEARCHING_LOG_CONFIGURATION=\
+ EELF0005I|\
+ Searching path "{0}" for log configuration file "{1}"|\
+ Verify the correct Path({user.home};etc;../etc) and filename (eelf.logging.file).|\
+ Searching path for specific log configuration file.
+UNSUPPORTED_LOGGING_FRAMEWORK=\
+ EELF0006E|\
+ An unsupported logging framework is bound to SLF4J. |\
+ Verify your logging frameworks.|\
+ An unsupported logging framework is bound to SLF4J. \ No newline at end of file
diff --git a/src/main/resources/cache.ccf b/src/main/resources/cache.ccf
new file mode 100644
index 00000000..acc6831c
--- /dev/null
+++ b/src/main/resources/cache.ccf
@@ -0,0 +1,56 @@
+# DEFAULT CACHE REGION
+jcs.default=
+jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes.MaxObjects=1000
+jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.UseMemoryShrinker=false
+jcs.default.cacheattributes.MaxMemoryIdleTime=3600
+jcs.default.cacheattributes.ShrinkerInterval=60
+jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.default.elementattributes.IsEternal=false
+jcs.default.elementattributes.MaxLife=21600
+jcs.default.elementattributes.IdleTime=1800
+jcs.default.elementattributes.IsSpool=true
+jcs.default.elementattributes.IsRemote=true
+jcs.default.elementattributes.IsLateral=true
+
+# PRE-DEFINED CACHE REGIONS
+jcs.region.musicCache=
+jcs.region.musicCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.musicCache.cacheattributes.MaxObjects=1000
+jcs.region.musicCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.musicCache.cacheattributes.UseMemoryShrinker=false
+jcs.region.musicCache.cacheattributes.MaxMemoryIdleTime=3600
+jcs.region.musicCache.cacheattributes.ShrinkerInterval=60
+jcs.region.musicCache.cacheattributes.MaxSpoolPerRun=500
+jcs.region.musicCache.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.musicCache.elementattributes.IsEternal=false
+
+
+# PRE-DEFINED CACHE REGIONS
+jcs.region.aafCache=
+jcs.region.aafCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.aafCache.cacheattributes.MaxObjects=1000
+jcs.region.aafCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.aafCache.cacheattributes.UseMemoryShrinker=false
+jcs.region.aafCache.cacheattributes.MaxMemoryIdleTime=3600
+jcs.region.aafCache.cacheattributes.ShrinkerInterval=60
+jcs.region.aafCache.cacheattributes.MaxSpoolPerRun=500
+jcs.region.aafCache.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.aafCache.elementattributes.IsEternal=false
+
+# PRE-DEFINED CACHE REGIONS
+jcs.region.appNameCache=
+jcs.region.appNameCache.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes
+jcs.region.appNameCache.cacheattributes.MaxObjects=1000
+jcs.region.appNameCache.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache
+jcs.region.appNameCache.cacheattributes.UseMemoryShrinker=false
+jcs.region.appNameCache.cacheattributes.MaxMemoryIdleTime=3600
+jcs.region.appNameCache.cacheattributes.ShrinkerInterval=60
+jcs.region.appNameCache.cacheattributes.MaxSpoolPerRun=500
+jcs.region.appNameCache.elementattributes=org.apache.commons.jcs.engine.ElementAttributes
+jcs.region.appNameCache.elementattributes.IsEternal=false
+
+
+
+
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
new file mode 100644
index 00000000..5378ebaf
--- /dev/null
+++ b/src/main/resources/logback.xml
@@ -0,0 +1,269 @@
+<!--
+ ============LICENSE_START==========================================
+ org.onap.music
+ ===================================================================
+ Copyright (c) 2017 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.
+
+ ============LICENSE_END=============================================
+ ====================================================================
+-->
+<configuration scan="true" scanPeriod="3 seconds">
+ <!--<jmxConfigurator /> -->
+ <!-- directory path for all other type logs -->
+ <property name="logDir" value="/opt/app/music/logs" />
+
+ <!-- directory path for debugging type logs -->
+ <property name="debugDir" value="debug-logs" />
+
+ <!-- specify the component name -->
+ <!-- <property name="componentName" value="EELF"></property> -->
+ <property name="componentName" value="MUSIC"></property>
+
+ <!-- log file names -->
+ <property name="generalLogName" value="music" />
+ <property name="securityLogName" value="security" />
+ <property name="errorLogName" value="error" />
+ <property name="metricsLogName" value="metrics" />
+ <property name="auditLogName" value="audit" />
+ <property name="debugLogName" value="debug" />
+ <property name="defaultPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n " />
+ <property name="auditLoggerPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Unused}|%X{ProcessKey}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}| %msg%n" />
+ <property name="metricsLoggerPattern" value="%X{BeginTimestamp}|%X{EndTimestamp}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{VirtualServerName}|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%X{StatusCode}|%X{ResponseCode}|%X{ResponseDescription}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ElapsedTime}|%X{ServerFQDN}|%X{RemoteHost}|%X{ClassName}|%X{Unused}|%X{ProcessKey}|%X{TargetVirtualEntity}|%X{CustomField1}|%X{CustomField2}|%X{CustomField3}|%X{CustomField4}| %msg%n" />
+ <property name="errorLoggerPattern" value="%date{ISO8601,UTC}|%X{RequestId}|%thread|%X{ServiceName}|%X{PartnerName}|%X{TargetEntity}|%X{TargetServiceName}|%.-5level|%X{ErrorCode}|%X{ErrorDescription}| %msg%n" />
+ <property name="debugLoggerPattern" value="%date{ISO8601,UTC}|%X{RequestId}| %msg%n" ></property>
+ <property name="logDirectory" value="${logDir}/${componentName}" />
+ <property name="debugLogDirectory" value="${debugDir}/${componentName}" />
+ <!-- Example evaluator filter applied against console appender -->
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <!-- <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder> -->
+ <layout class="">
+ <pattern>
+ %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
+ </pattern>
+ </layout>
+ </appender>
+
+ <!-- ============================================================================ -->
+ <!-- EELF Appenders -->
+ <!-- ============================================================================ -->
+ <appender name="EELF"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${generalLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${generalLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="asyncEELF" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <includeCallerData>true</includeCallerData>
+ <appender-ref ref="EELF" />
+ </appender>
+
+ <!-- EELF Security Appender. This appender is used to record security events
+ to the security log file. Security events are separate from other loggers
+ in EELF so that security log records can be captured and managed in a secure
+ way separate from the other logs. This appender is set to never discard any
+ events. -->
+ <appender name="EELFSecurity"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${securityLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${securityLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n </pattern>
+ </encoder>
+ </appender>
+
+ <appender name="asyncEELFSecurity" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <discardingThreshold>0</discardingThreshold>
+ <appender-ref ref="EELFSecurity" />
+ </appender>
+
+
+
+
+ <!-- EELF Audit Appender. This appender is used to record audit engine
+ related logging events. The audit logger and appender are specializations
+ of the EELF application root logger and appender. This can be used to segregate
+ Policy engine events from other components, or it can be eliminated to record
+ these events as part of the application root log. -->
+
+ <appender name="EELFAudit"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${auditLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${auditLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${auditLoggerPattern}</pattern>
+ </encoder>
+ </appender>
+ <appender name="asyncEELFAudit" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFAudit" />
+ </appender>
+
+<appender name="EELFMetrics"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${metricsLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${metricsLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <!-- <pattern>"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} -
+ %msg%n"</pattern> -->
+ <pattern>${metricsLoggerPattern}</pattern>
+ </encoder>
+ </appender>
+
+
+ <appender name="asyncEELFMetrics" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFMetrics"/>
+ </appender>
+
+ <appender name="EELFError"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${logDirectory}/${errorLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${logDirectory}/${errorLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="asyncEELFError" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFError"/>
+ </appender>
+
+ <appender name="EELFDebug"
+ class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>${debugLogDirectory}/${debugLogName}.log</file>
+ <rollingPolicy
+ class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>${debugLogDirectory}/${debugLogName}.%i.log.zip
+ </fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>9</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy
+ class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>5MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>${defaultPattern}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="asyncEELFDebug" class="ch.qos.logback.classic.AsyncAppender">
+ <queueSize>256</queueSize>
+ <appender-ref ref="EELFDebug" />
+ <includeCallerData>true</includeCallerData>
+ </appender>
+
+
+ <!-- ============================================================================ -->
+ <!-- EELF loggers -->
+ <!-- ============================================================================ -->
+ <logger name="com.att.eelf" level="info" additivity="false">
+ <appender-ref ref="asyncEELF" />
+
+ </logger>
+ <logger name="com.att.eelf.security" level="info" additivity="false">
+ <appender-ref ref="asyncEELFSecurity" />
+
+ </logger>
+
+
+ <logger name="com.att.eelf.audit" level="info" additivity="false">
+ <appender-ref ref="asyncEELFAudit" />
+
+ </logger>
+
+ <logger name="com.att.eelf.metrics" level="info" additivity="false">
+ <appender-ref ref="asyncEELFMetrics" />
+
+ </logger>
+
+
+ <logger name="com.att.eelf.error" level="error" additivity="false">
+ <appender-ref ref="asyncEELFError" />
+
+ </logger>
+
+ <logger name="com.att.eelf.debug" level="debug" additivity="false">
+ <appender-ref ref="asyncEELFDebug" />
+
+ </logger>
+
+
+
+
+ <root level="INFO">
+ <appender-ref ref="asyncEELF" />
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>
diff --git a/src/main/resources/project.properties b/src/main/resources/project.properties
new file mode 100644
index 00000000..199afa33
--- /dev/null
+++ b/src/main/resources/project.properties
@@ -0,0 +1,4 @@
+version=${project.version}
+artifactId=${project.artifactId}
+music.properties=/opt/app/music/etc/music.properties
+