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