1 /*******************************************************************************
\r
2 * ============LICENSE_START====================================================
\r
4 * * ===========================================================================
\r
5 * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
\r
6 * * ===========================================================================
\r
7 * * Licensed under the Apache License, Version 2.0 (the "License");
\r
8 * * you may not use this file except in compliance with the License.
\r
9 * * You may obtain a copy of the License at
\r
11 * * http://www.apache.org/licenses/LICENSE-2.0
\r
13 * * Unless required by applicable law or agreed to in writing, software
\r
14 * * distributed under the License is distributed on an "AS IS" BASIS,
\r
15 * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
16 * * See the License for the specific language governing permissions and
\r
17 * * limitations under the License.
\r
18 * * ============LICENSE_END====================================================
\r
20 * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
\r
22 ******************************************************************************/
\r
23 package org.onap.aaf.dao;
\r
25 import java.io.IOException;
\r
26 import java.util.ArrayList;
\r
27 import java.util.List;
\r
29 import org.onap.aaf.authz.env.AuthzEnv;
\r
31 import org.onap.aaf.cadi.routing.GreatCircle;
\r
32 import org.onap.aaf.inno.env.APIException;
\r
33 import org.onap.aaf.inno.env.Env;
\r
34 import org.onap.aaf.inno.env.util.Split;
\r
35 import com.datastax.driver.core.Cluster;
\r
36 import com.datastax.driver.core.Cluster.Builder;
\r
37 import com.datastax.driver.core.policies.DCAwareRoundRobinPolicy;
\r
39 public class CassAccess {
\r
40 public static final String KEYSPACE = "authz";
\r
41 public static final String CASSANDRA_CLUSTERS = "cassandra.clusters";
\r
42 public static final String CASSANDRA_CLUSTERS_PORT = "cassandra.clusters.port";
\r
43 public static final String CASSANDRA_CLUSTERS_USER_NAME = "cassandra.clusters.user";
\r
44 public static final String CASSANDRA_CLUSTERS_PASSWORD = "cassandra.clusters.password";
\r
45 public static final String CASSANDRA_RESET_EXCEPTIONS = "cassandra.reset.exceptions";
\r
46 public static final String LATITUDE = "LATITUDE";
\r
47 public static final String LONGITUDE = "LONGITUDE";
\r
48 private static final List<Resettable> resetExceptions = new ArrayList<Resettable>();
\r
49 public static final String ERR_ACCESS_MSG = "Accessing Backend";
\r
50 private static Builder cb = null;
\r
53 * To create DCAwareRoundRobing Policy:
\r
55 * LATITUDE (or AFT_LATITUDE)
\r
56 * LONGITUDE (or AFT_LONGITUDE)
\r
57 * CASSANDRA CLUSTERS with additional information:
\r
58 * machine:DC:lat:long,machine:DC:lat:long
\r
62 * @throws APIException
\r
63 * @throws IOException
\r
66 @SuppressWarnings("deprecation")
\r
67 public static synchronized Cluster cluster(Env env, String prefix) throws APIException, IOException {
\r
73 env.info().log("Cassandra Connection for ",prefix);
\r
76 cb = Cluster.builder();
\r
77 String str = env.getProperty(pre+CASSANDRA_CLUSTERS_PORT,"9042");
\r
79 env.init().log("Cass Port = ",str );
\r
80 cb.withPort(Integer.parseInt(str));
\r
82 str = env.getProperty(pre+CASSANDRA_CLUSTERS_USER_NAME,null);
\r
84 env.init().log("Cass User = ",str );
\r
85 String epass = env.getProperty(pre + CASSANDRA_CLUSTERS_PASSWORD,null);
\r
87 throw new APIException("No Password configured for " + str);
\r
89 //TODO Figure out way to ensure Decryptor setting in AuthzEnv
\r
90 if(env instanceof AuthzEnv) {
\r
91 cb.withCredentials(str,((AuthzEnv)env).decrypt(epass,true));
\r
93 cb.withCredentials(str, env.decryptor().decrypt(epass));
\r
97 str = env.getProperty(pre+CASSANDRA_RESET_EXCEPTIONS,null);
\r
99 env.init().log("Cass ResetExceptions = ",str );
\r
100 for(String ex : Split.split(',', str)) {
\r
101 resetExceptions.add(new Resettable(env,ex));
\r
105 str = env.getProperty(LATITUDE,env.getProperty("AFT_LATITUDE",null));
\r
106 Double lat = str!=null?Double.parseDouble(str):null;
\r
107 str = env.getProperty(LONGITUDE,env.getProperty("AFT_LONGITUDE",null));
\r
108 Double lon = str!=null?Double.parseDouble(str):null;
\r
109 if(lat == null || lon == null) {
\r
110 throw new APIException("LATITUDE(or AFT_LATITUDE) and/or LONGITUDE(or AFT_LATITUDE) are not set");
\r
113 env.init().printf("Service Latitude,Longitude = %f,%f",lat,lon);
\r
115 str = env.getProperty(pre+CASSANDRA_CLUSTERS,"localhost");
\r
116 env.init().log("Cass Clusters = ",str );
\r
117 String[] machs = Split.split(',', str);
\r
118 String[] cpoints = new String[machs.length];
\r
119 String bestDC = null;
\r
120 int numInBestDC = 1;
\r
121 double mlat, mlon,temp,distance = -1.0;
\r
122 for(int i=0;i<machs.length;++i) {
\r
123 String[] minfo = Split.split(':',machs[i]);
\r
124 if(minfo.length>0) {
\r
125 cpoints[i]=minfo[0];
\r
128 // Calc closest DC with Great Circle
\r
129 if(minfo.length>3) {
\r
130 mlat = Double.parseDouble(minfo[2]);
\r
131 mlon = Double.parseDouble(minfo[3]);
\r
132 if((temp=GreatCircle.calc(lat, lon, mlat, mlon)) > distance) {
\r
134 if(bestDC!=null && bestDC.equals(minfo[1])) {
\r
141 if(bestDC!=null && bestDC.equals(minfo[1])) {
\r
148 cb.addContactPoints(cpoints);
\r
151 // 8/26/2016 Management has determined that Accuracy is preferred over speed in bad situations
\r
152 // Local DC Aware Load Balancing appears to have the highest normal performance, with the best
\r
153 // Degraded Accuracy
\r
154 cb.withLoadBalancingPolicy(new DCAwareRoundRobinPolicy(
\r
155 bestDC, numInBestDC, true /*allow LocalDC to look at other DCs for LOCAL_QUORUM */));
\r
156 env.init().printf("Cassandra configured for DCAwareRoundRobinPolicy at %s with emergency remote of up to %d node(s)"
\r
157 ,bestDC, numInBestDC);
\r
159 env.init().printf("Cassandra is using Default Policy, which is not DC aware");
\r
165 private static class Resettable {
\r
166 private Class<? extends Exception> cls;
\r
167 private List<String> messages;
\r
169 @SuppressWarnings("unchecked")
\r
170 public Resettable(Env env, String propData) throws APIException {
\r
171 if(propData!=null && propData.length()>1) {
\r
172 String[] split = Split.split(':', propData);
\r
173 if(split.length>0) {
\r
175 cls = (Class<? extends Exception>)Class.forName(split[0]);
\r
176 } catch (ClassNotFoundException e) {
\r
177 throw new APIException("Declared Cassandra Reset Exception, " + propData + ", cannot be ClassLoaded");
\r
180 if(split.length>1) {
\r
181 messages=new ArrayList<String>();
\r
182 for(int i=1;i<split.length;++i) {
\r
183 String str = split[i];
\r
184 int start = str.startsWith("\"")?1:0;
\r
185 int end = str.length()-(str.endsWith("\"")?1:0);
\r
186 messages.add(split[i].substring(start, end));
\r
194 public boolean matches(Exception ex) {
\r
195 if(ex.getClass().equals(cls)) {
\r
196 if(messages!=null) {
\r
197 String msg = ex.getMessage();
\r
198 for(String m : messages) {
\r
199 if(msg.contains(m)) {
\r
209 public static final boolean isResetException(Exception e) {
\r
213 for(Resettable re : resetExceptions) {
\r
214 if(re.matches(e)) {
\r