Support system variables in property values 50/83050/3
authorRich Tabedzki <richard.tabedzki@att.com>
Fri, 22 Mar 2019 15:01:50 +0000 (11:01 -0400)
committerRich Tabedzki <richard.tabedzki@att.com>
Fri, 22 Mar 2019 19:21:13 +0000 (15:21 -0400)
Changes made:
* Added code in DBResourceManager to replace  with its value
* Expanded debug statement by adding processing time

Change-Id: I22748daed50063e8e0ac7201e88d69a2609c1788
Issue-ID: CCSDK-1133
Signed-off-by: Rich Tabedzki <richard.tabedzki@att.com>
dblib/provider/src/main/java/org/onap/ccsdk/sli/core/dblib/CachedDataSource.java
dblib/provider/src/main/java/org/onap/ccsdk/sli/core/dblib/DBResourceManager.java
dblib/provider/src/main/java/org/onap/ccsdk/sli/core/dblib/TerminatingCachedDataSource.java

index bc466d9..b9a0f07 100755 (executable)
@@ -33,6 +33,7 @@ import java.sql.SQLException;
 import java.sql.Statement;
 import java.sql.Timestamp;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Observer;
 import javax.sql.DataSource;
@@ -59,7 +60,7 @@ public abstract class CachedDataSource implements DataSource, SQLExecutionMonito
     private static final Logger LOGGER = LoggerFactory.getLogger(CachedDataSource.class);
 
     private static final String SQL_FAILURE = "SQL FAILURE. time(ms): ";
-    private static final String FAILED_TO_EXECUTE = "> failed to execute: ";
+    private static final String FAILED_TO_EXECUTE = "> Failed to execute: ";
     private static final String WITH_ARGUMENTS = " with arguments: ";
     private static final String WITH_NO_ARGUMENTS = " with no arguments. ";
     private static final String DATA_SOURCE_CONNECT_SUCCESS = "SQL DataSource < {} > connected to {}, read-only is {}, tested successfully";
@@ -82,12 +83,13 @@ public abstract class CachedDataSource implements DataSource, SQLExecutionMonito
     private long nextErrorReportTime = 0L;
 
     private String globalHostName = null;
+    private final int index;
 
     private boolean isDerby = false;
 
     public CachedDataSource(BaseDBConfiguration jdbcElem) throws DBConfigException {
         ds = configure(jdbcElem);
-
+        index = initializeIndex(jdbcElem);
         if ("org.apache.derby.jdbc.EmbeddedDriver".equals(jdbcElem.getDriverName())) {
             isDerby = true;
         }
@@ -97,6 +99,16 @@ public abstract class CachedDataSource implements DataSource, SQLExecutionMonito
     protected abstract DataSource configure(BaseDBConfiguration jdbcElem) throws DBConfigException;
     protected abstract int getAvailableConnections();
 
+    protected int initializeIndex(BaseDBConfiguration jdbcElem) {
+        if(jdbcElem.containsKey(BaseDBConfiguration.DATABASE_HOSTS)) {
+            String hosts = jdbcElem.getProperty(BaseDBConfiguration.DATABASE_HOSTS);
+            String name = jdbcElem.getProperty(BaseDBConfiguration.CONNECTION_NAME);
+            List<String> numbers = Arrays.asList(hosts.split(","));
+            return numbers.indexOf(name);
+        } else
+            return -1;
+    }
+
     /*
      * (non-Javadoc)
      *
@@ -104,7 +116,14 @@ public abstract class CachedDataSource implements DataSource, SQLExecutionMonito
      */
     @Override
     public Connection getConnection() throws SQLException {
+        LapsedTimer lt = new LapsedTimer();
+        try {
         return ds.getConnection();
+        } finally {
+            if(LOGGER.isTraceEnabled()) {
+                LOGGER.trace(String.format("SQL Connection aquisition time : %s", lt.lapsedTime()));
+            }
+        }
     }
 
     public CachedRowSet getData(String statement, List<Object> arguments) throws SQLException {
@@ -397,6 +416,10 @@ public abstract class CachedDataSource implements DataSource, SQLExecutionMonito
         monitor.deleteObserver(observer);
     }
 
+    public int getIndex() {
+        return index;
+    }
+
     @Override
     public long getInterval() {
         return interval;
@@ -487,9 +510,9 @@ public abstract class CachedDataSource implements DataSource, SQLExecutionMonito
             isSlave = true;
         }
         if (isSlave) {
-            LOGGER.debug("SQL SLAVE : {} on server {}, pool {}", connectionName, hostname, getAvailableConnections());
+            LOGGER.debug("SQL SLAVE : {} on server {}, pool {}", connectionName, getDbConnectionName(), getAvailableConnections());
         } else {
-            LOGGER.debug("SQL MASTER : {} on server {}, pool {}", connectionName, hostname, getAvailableConnections());
+            LOGGER.debug("SQL MASTER : {} on server {}, pool {}", connectionName, getDbConnectionName(), getAvailableConnections());
         }
         return isSlave;
     }
@@ -557,4 +580,14 @@ public abstract class CachedDataSource implements DataSource, SQLExecutionMonito
     public String getGlobalHostName() {
         return globalHostName;
     }
+
+    static class LapsedTimer {
+        private final long msTime = System.currentTimeMillis();
+        public String lapsedTime() {
+            double timediff = System.currentTimeMillis() - msTime;
+            timediff = timediff/1000;
+            return String.valueOf( timediff)+"s";
+        }
+    }
 }
index 236bce6..7c71bcc 100755 (executable)
@@ -35,6 +35,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Map;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Observable;
@@ -44,6 +45,7 @@ import java.util.SortedSet;
 import java.util.TimerTask;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.stream.Collectors;
 
 import javax.sql.DataSource;
 import javax.sql.rowset.CachedRowSet;
@@ -66,7 +68,8 @@ import org.slf4j.LoggerFactory;
  * Rich Tabedzki
  */
 public class DBResourceManager implements DataSource, DataAccessor, DBResourceObserver, DbLibService {
-    private static Logger LOGGER = LoggerFactory.getLogger(DBResourceManager.class);
+    private static final Logger LOGGER = LoggerFactory.getLogger(DBResourceManager.class);
+    private static final String DATABASE_URL = "org.onap.ccsdk.sli.jdbc.url";
 
     transient boolean terminating = false;
     transient protected long retryInterval = 10000L;
@@ -92,8 +95,8 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
     }
 
     public DBResourceManager(final Properties properties) {
-        this.configProps = properties;
-        
+        this.configProps = processSystemVariables(properties);
+
         // TODO : hack to force classloader to cache mariadb driver.  This shouldnt be necessary,
         // but for some reason it is (without this, dblib throws ClassNotFound on mariadb driver
         // and fails to load).
@@ -102,26 +105,26 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
         dvr = null;
 
         // get retry interval value
-        retryInterval = getLongFromProperties(properties, "org.onap.dblib.connection.retry", 10000L);
+        retryInterval = getLongFromProperties(configProps, "org.onap.dblib.connection.retry", 10000L);
 
         // get recovery mode flag
-        recoveryMode = getBooleanFromProperties(properties, "org.onap.dblib.connection.recovery", true);
+        recoveryMode = getBooleanFromProperties(configProps, "org.onap.dblib.connection.recovery", true);
         if(!recoveryMode)
         {
             recoveryMode = false;
             LOGGER.info("Recovery Mode disabled");
         }
         // get time out value for thread cleanup
-        terminationTimeOut = getLongFromProperties(properties, "org.onap.dblib.termination.timeout", 300000L);
+        terminationTimeOut = getLongFromProperties(configProps, "org.onap.dblib.termination.timeout", 300000L);
         // get properties for monitoring
-        monitorDbResponse = getBooleanFromProperties(properties, "org.onap.dblib.connection.monitor", false);
-        monitoringInterval = getLongFromProperties(properties, "org.onap.dblib.connection.monitor.interval", 1000L);
-        monitoringInitialDelay = getLongFromProperties(properties, "org.onap.dblib.connection.monitor.startdelay", 5000L);
-        expectedCompletionTime = getLongFromProperties(properties, "org.onap.dblib.connection.monitor.expectedcompletiontime", 5000L);
-        unprocessedFailoverThreshold = getLongFromProperties(properties, "org.onap.dblib.connection.monitor.unprocessedfailoverthreshold", 3L);
+        monitorDbResponse = getBooleanFromProperties(configProps, "org.onap.dblib.connection.monitor", false);
+        monitoringInterval = getLongFromProperties(configProps, "org.onap.dblib.connection.monitor.interval", 1000L);
+        monitoringInitialDelay = getLongFromProperties(configProps, "org.onap.dblib.connection.monitor.startdelay", 5000L);
+        expectedCompletionTime = getLongFromProperties(configProps, "org.onap.dblib.connection.monitor.expectedcompletiontime", 5000L);
+        unprocessedFailoverThreshold = getLongFromProperties(configProps, "org.onap.dblib.connection.monitor.unprocessedfailoverthreshold", 3L);
 
         // initialize performance monitor
-        PollingWorker.createInistance(properties);
+        PollingWorker.createInistance(configProps);
 
         // initialize recovery thread
         worker = new RecoveryMgr();
@@ -130,13 +133,49 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
         worker.start();
 
         try {
-            this.config(properties);
+            this.config(configProps);
         } catch (final Exception e) {
             // TODO: config throws <code>Exception</code> which is poor practice.  Eliminate this in a separate patch.
             LOGGER.error("Fatal Exception encountered while configuring DBResourceManager", e);
         }
     }
 
+    public static Properties processSystemVariables(Properties properties) {
+        Map<Object, Object> hmap = new Properties();
+        hmap.putAll(properties);
+
+        Map<Object, Object> result = hmap.entrySet().stream()
+            .filter(map -> map.getValue().toString().startsWith("${"))
+            .filter(map -> map.getValue().toString().endsWith("}"))
+            .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue()));
+
+        result.forEach((name, propEntries) -> {
+            hmap.put(name, replace(propEntries.toString()));
+        });
+
+        if(hmap.containsKey(DATABASE_URL) && hmap.get(DATABASE_URL).toString().contains("${")) {
+            String url = hmap.get(DATABASE_URL).toString();
+            String[] innerChunks = url.split("\\$\\{");
+            for(String chunk : innerChunks) {
+                if(chunk.contains("}")) {
+                    String subChunk = chunk.substring(0, chunk.indexOf("}"));
+                    String varValue = System.getenv(subChunk);
+                    url = url.replace("${"+subChunk+"}", varValue);
+                }
+            }
+            hmap.put(DATABASE_URL, url);
+        }
+        return Properties.class.cast(hmap);
+      }
+
+
+      private static String replace(String value) {
+          String globalVariable = value.substring(2, value.length() -1);
+          String varValue = System.getenv(globalVariable);
+          return  (varValue != null) ? varValue : value;
+      }
+
+
     private void config(Properties configProps) throws Exception {
         final ConcurrentLinkedQueue<CachedDataSource> semaphore = new ConcurrentLinkedQueue<>();
         final DbConfigPool dbConfig = DBConfigFactory.createConfig(configProps);
@@ -204,11 +243,33 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
                     return -1;
                 }
 
-                if(!left.isSlave())
+                boolean leftMaster = !left.isSlave();
+                if(leftMaster) {
+                    if(left.getIndex() <= right.getIndex())
+                        return -1;
+                    else {
+                        boolean rightMaster = !right.isSlave();
+                        if(rightMaster) {
+                            if(left.getIndex() <= right.getIndex())
+                                return -1;
+//                            if(left.getIndex() > right.getIndex())
+                            else {
+                                return 1;
+                            }
+                        } else {
                     return -1;
+                        }
+                    }
+                }
                 if(!right.isSlave())
                     return 1;
 
+                if(left.getIndex() <= right.getIndex())
+                    return -1;
+                if(left.getIndex() > right.getIndex())
+                    return 1;
+
+
             } catch (Throwable e) {
                 LOGGER.warn("", e);
             }
@@ -440,12 +501,12 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
                     }
                 }
                 lastException = exc;
-                LOGGER.error("Generated alarm: "+active.getDbConnectionName(), exc);
+                LOGGER.error("Generated alarm: {}", active.getDbConnectionName(), exc);
                 handleGetConnectionException(active, exc);
             } finally {
                 if(LOGGER.isDebugEnabled()){
                     time = System.currentTimeMillis() - time;
-                    LOGGER.debug("getData processing time : "+ active.getDbConnectionName()+"  "+time+" miliseconds.");
+                    LOGGER.debug("getData processing time : {} {} miliseconds.", active.getDbConnectionName(), time);
                 }
             }
         }
@@ -490,7 +551,7 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
             String message = exc.getMessage();
             if(message == null)
                 message = exc.getClass().getName();
-            LOGGER.error("Generated alarm: "+active.getDbConnectionName()+" - "+message);
+            LOGGER.error("Generated alarm: {} - {}",active.getDbConnectionName(), message);
             if(exc instanceof SQLException)
                 throw (SQLException)exc;
             else {
@@ -501,7 +562,7 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
         } finally {
             if(LOGGER.isDebugEnabled()){
                 time = System.currentTimeMillis() - time;
-                LOGGER.debug(">> getData : "+ active.getDbConnectionName()+"  "+time+" miliseconds.");
+                LOGGER.debug(">> getData : {} {}  miliseconds.", active.getDbConnectionName(), time);
             }
         }
     }
@@ -570,12 +631,12 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
                 String message = exc.getMessage();
                 if(message == null)
                     message = exc.getClass().getName();
-                LOGGER.error("Generated alarm: "+active.getDbConnectionName()+" - "+message);
+                LOGGER.error("Generated alarm: {} - {}", active.getDbConnectionName(), message);
                 if(exc instanceof SQLException) {
                     SQLException sqlExc = SQLException.class.cast(exc);
                     // handle read-only exception
                     if(sqlExc.getErrorCode() == 1290 && "HY000".equals(sqlExc.getSQLState())) {
-                        LOGGER.warn("retrying due to: " + sqlExc.getMessage());
+                        LOGGER.warn("retrying due to: {}", sqlExc.getMessage());
                         this.findMaster();
                         if(retryAllowed){
                             retryAllowed = false;
@@ -592,7 +653,7 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
             } finally {
                 if(LOGGER.isDebugEnabled()){
                     time = System.currentTimeMillis() - time;
-                    LOGGER.debug("writeData processing time : "+ active.getDbConnectionName()+"  "+time+" miliseconds.");
+                    LOGGER.debug("writeData processing time : {} {} miliseconds.", active.getDbConnectionName(), time);
                 }
             }
         }
@@ -626,6 +687,7 @@ public class DBResourceManager implements DataSource, DataAccessor, DBResourceOb
 
             if(!active.isFabric()) {
                 if(this.dsQueue.size() > 1 && active.isSlave()) {
+                LOGGER.debug("Forcing reorder on: {}", dsQueue.toString());
                     CachedDataSource master = findMaster();
                     if(master != null) {
                         active = master;
index 884f888..852dda3 100755 (executable)
@@ -30,6 +30,7 @@ import org.onap.ccsdk.sli.core.dblib.pm.SQLExecutionMonitorObserver;
 public class TerminatingCachedDataSource extends CachedDataSource implements SQLExecutionMonitorObserver {
 
     private static final int DEFAULT_AVAILABLE_CONNECTIONS = 0;
+       private static final int DEFAULT_INDEX = -1;
 
     public TerminatingCachedDataSource(BaseDBConfiguration jdbcElem) throws DBConfigException {
         super(jdbcElem);
@@ -49,4 +50,10 @@ public class TerminatingCachedDataSource extends CachedDataSource implements SQL
     protected int getAvailableConnections() {
         return DEFAULT_AVAILABLE_CONNECTIONS;
     }
+
+    @Override
+    protected int initializeIndex(BaseDBConfiguration jdbcElem) {
+           return DEFAULT_INDEX;
+    }
+
 }