summaryrefslogtreecommitdiffstats
path: root/client/src/main/java/com/att
diff options
context:
space:
mode:
authorsg481n <sg481n@att.com>2017-08-03 17:39:12 -0400
committersg481n <sg481n@att.com>2017-08-03 17:39:12 -0400
commit4a51a8f96715ffb2a42189b93b9fa91b453b8530 (patch)
treeb028ce9e44920addba4194643db5b1c115a00e1a /client/src/main/java/com/att
parent81ad32335f59a3169c032139fb77148b247ed7f0 (diff)
 [AAF-21] Initial code import
Change-Id: Ia1dd196befd061f6ba0c2be6bf4456a30ea50f97 Signed-off-by: sg481n <sg481n@att.com>
Diffstat (limited to 'client/src/main/java/com/att')
-rw-r--r--client/src/main/java/com/att/cadi/client/AAFClient.java199
-rw-r--r--client/src/main/java/com/att/cadi/client/AbsBasicAuth.java94
-rw-r--r--client/src/main/java/com/att/cadi/client/AbsTransferSS.java74
-rw-r--r--client/src/main/java/com/att/cadi/client/Delete.java71
-rw-r--r--client/src/main/java/com/att/cadi/client/EClient.java53
-rw-r--r--client/src/main/java/com/att/cadi/client/EnvAccess.java168
-rw-r--r--client/src/main/java/com/att/cadi/client/Future.java35
-rw-r--r--client/src/main/java/com/att/cadi/client/Get.java49
-rw-r--r--client/src/main/java/com/att/cadi/client/Holder.java45
-rw-r--r--client/src/main/java/com/att/cadi/client/Post.java50
-rw-r--r--client/src/main/java/com/att/cadi/client/PropertyLocator.java144
-rw-r--r--client/src/main/java/com/att/cadi/client/Put.java65
-rw-r--r--client/src/main/java/com/att/cadi/client/RawClient.java159
-rw-r--r--client/src/main/java/com/att/cadi/client/Rcli.java697
-rw-r--r--client/src/main/java/com/att/cadi/client/Result.java58
-rw-r--r--client/src/main/java/com/att/cadi/client/Retryable.java72
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DEClient.java223
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java64
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java65
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2Locator.java349
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java56
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DME2x509SS.java68
-rw-r--r--client/src/main/java/com/att/cadi/dme2/DRcli.java142
-rw-r--r--client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java168
-rw-r--r--client/src/main/java/com/att/cadi/http/HBasicAuthSS.java77
-rw-r--r--client/src/main/java/com/att/cadi/http/HClient.java434
-rw-r--r--client/src/main/java/com/att/cadi/http/HMangr.java236
-rw-r--r--client/src/main/java/com/att/cadi/http/HRcli.java134
-rw-r--r--client/src/main/java/com/att/cadi/http/HTransferSS.java66
-rw-r--r--client/src/main/java/com/att/cadi/http/HX509SS.java168
-rw-r--r--client/src/main/java/com/att/cadi/locator/DME2Locator.java346
-rw-r--r--client/src/main/java/com/att/cadi/locator/DNSLocator.java164
-rw-r--r--client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java62
-rw-r--r--client/src/main/java/com/att/cadi/locator/HotPeerLocator.java304
-rw-r--r--client/src/main/java/com/att/cadi/locator/PropertyLocator.java282
-rw-r--r--client/src/main/java/com/att/cadi/routing/GreatCircle.java190
36 files changed, 5631 insertions, 0 deletions
diff --git a/client/src/main/java/com/att/cadi/client/AAFClient.java b/client/src/main/java/com/att/cadi/client/AAFClient.java
new file mode 100644
index 0000000..843f3b1
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/AAFClient.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.net.HttpURLConnection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.cadi.Access;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.http.HBasicAuthSS;
+import com.att.cadi.http.HMangr;
+import com.att.cadi.locator.DME2Locator;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+import com.att.rosetta.env.RosettaEnv;
+
+public class AAFClient {
+ private RosettaEnv env;
+ private Map<Class<?>,RosettaDF<?>> map = new HashMap<Class<?>,RosettaDF<?>>();
+ HMangr hman;
+ HBasicAuthSS ss;
+
+ public AAFClient(RosettaEnv env) throws Exception {
+ this.env = env;
+ Access access = new EnvAccess(env);
+ String user = access.getProperty(Config.AAF_MECHID,null);
+ String password = access.decrypt(access.getProperty(Config.AAF_MECHPASS,null), true);
+
+ SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);
+ DME2Manager dm = new DME2Manager("APIclient DME2Manager", System.getProperties());
+ DME2Locator loc = new DME2Locator(access, dm, access.getProperty(Config.AAF_URL,null));
+
+ int TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, "30000"));
+
+ hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion("2.0");
+ ss = new HBasicAuthSS(user, password, si);
+ }
+
+ public AAFClient(RosettaEnv env, DME2Manager dm) throws Exception {
+ this.env = env;
+ Access access = new EnvAccess(env);
+ String user = access.getProperty(Config.AAF_MECHID,null);
+ String password = access.decrypt(access.getProperty(Config.AAF_MECHPASS,null), true);
+
+ SecurityInfoC<HttpURLConnection> si = new SecurityInfoC<HttpURLConnection>(access);
+ DME2Locator loc = new DME2Locator(access, dm, access.getProperty(Config.AAF_URL,null));
+
+ int TIMEOUT = Integer.parseInt(access.getProperty(Config.AAF_CONN_TIMEOUT, "30000"));
+
+ hman = new HMangr(access, loc).readTimeout(TIMEOUT).apiVersion("2.0");
+ ss = new HBasicAuthSS(user, password, si);
+ }
+
+ @SuppressWarnings("unchecked")
+ private synchronized<T> RosettaDF<T> getDF(Class<T> cls) throws APIException {
+ RosettaDF<?> rdf;
+ synchronized (env) {
+ rdf = map.get(cls);
+ if(rdf==null) {
+ rdf = env.newDataFactory(cls);
+ map.put(cls, rdf);
+ }
+ }
+ return (RosettaDF<T>)rdf;
+ }
+
+ // Package on purpose
+ static class Call<T> {
+ protected final static String VOID_CONTENT_TYPE="application/Void+json;version=2.0";
+
+ protected RosettaDF<T> df;
+ protected AAFClient client;
+
+ public Call(AAFClient ac, RosettaDF<T> df) {
+ this.client = ac;
+ this.df = df;
+ }
+ }
+
+
+ /////////// Calls /////////////////
+ /**
+ * Returns a Get Object... same as "get"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Get<T> read(Class<T> cls) throws APIException {
+ return new Get<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Get Object... same as "read"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Get<T> get(Class<T> cls) throws APIException {
+ return new Get<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Post Object... same as "create"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Post<T> post(Class<T> cls) throws APIException {
+ return new Post<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Post Object... same as "post"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Post<T> create(Class<T> cls) throws APIException {
+ return new Post<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Put Object... same as "update"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Put<T> put(Class<T> cls) throws APIException {
+ return new Put<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Put Object... same as "put"
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Put<T> update(Class<T> cls) throws APIException {
+ return new Put<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Delete Object
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public<T> Delete<T> delete(Class<T> cls) throws APIException {
+ return new Delete<T>(this,getDF(cls));
+ }
+
+ /**
+ * Returns a Delete Object
+ *
+ * @param cls
+ * @return
+ * @throws APIException
+ */
+ public Delete<Void> delete() throws APIException {
+ return new Delete<Void>(this,null);
+ }
+
+ public Put<Void> put() {
+ return new Put<Void>(this,null);
+ }
+
+
+}
diff --git a/client/src/main/java/com/att/cadi/client/AbsBasicAuth.java b/client/src/main/java/com/att/cadi/client/AbsBasicAuth.java
new file mode 100644
index 0000000..ef8abf4
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/AbsBasicAuth.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.IOException;
+
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.Symm;
+import com.att.cadi.config.SecurityInfoC;
+
+public abstract class AbsBasicAuth<CLIENT> implements SecuritySetter<CLIENT> {
+ protected static final String REPEAT_OFFENDER="This call is aborted because of repeated usage of invalid Passwords";
+ private static final int MAX_TEMP_COUNT = 10;
+ private static final int MAX_SPAM_COUNT = 10000;
+ private static final long WAIT_TIME = 1000*60*4;
+
+ protected final String headValue;
+ protected SecurityInfoC<CLIENT> securityInfo;
+ protected String user;
+ private long lastMiss;
+ private int count;
+
+ public AbsBasicAuth(String user, String pass, SecurityInfoC<CLIENT> si) throws IOException {
+ this.user = user;
+ headValue = "Basic " + Symm.base64.encode(user + ':' + pass);
+ securityInfo = si;
+ lastMiss=0L;
+ count=0;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return user;
+ }
+
+ public boolean isDenied() {
+ if(lastMiss>0 && lastMiss>System.currentTimeMillis()) {
+ return true;
+ } else {
+ lastMiss=0L;
+ return false;
+ }
+ }
+
+ public synchronized int setLastResponse(int httpcode) {
+ if(httpcode == 401) {
+ ++count;
+ if(lastMiss==0L && count>MAX_TEMP_COUNT) {
+ lastMiss=System.currentTimeMillis()+WAIT_TIME;
+ }
+// if(count>MAX_SPAM_COUNT) {
+// System.err.printf("Your service has %d consecutive bad service logins to AAF. \nIt will now exit\n",
+// count);
+// System.exit(401);
+// }
+ if(count%1000==0) {
+ System.err.printf("Your service has %d consecutive bad service logins to AAF. AAF Access will be disabled after %d\n",
+ count,MAX_SPAM_COUNT);
+ }
+
+ } else {
+ lastMiss=0;
+ }
+ return count;
+ }
+
+ public int count() {
+ return count;
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/client/AbsTransferSS.java b/client/src/main/java/com/att/cadi/client/AbsTransferSS.java
new file mode 100644
index 0000000..3056187
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/AbsTransferSS.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.security.Principal;
+
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.principal.BasicPrincipal;
+import com.att.cadi.principal.TGuardPrincipal;
+import com.att.cadi.principal.TrustPrincipal;
+
+public abstract class AbsTransferSS<CLIENT> implements SecuritySetter<CLIENT> {
+ protected String value;
+ protected SecurityInfoC<CLIENT> securityInfo;
+ protected SecuritySetter<CLIENT> defSS;
+ private Principal principal;
+
+ //Format:<ID>:<APP>:<protocol>[:AS][,<ID>:<APP>:<protocol>]*
+ public AbsTransferSS(Principal principal, String app) {
+ init(principal, app);
+ }
+
+ public AbsTransferSS(Principal principal, String app, SecurityInfoC<CLIENT> si) {
+ init(principal,app);
+ securityInfo = si;
+ this.defSS = si.defSS;
+ }
+
+ private void init(Principal principal, String app) {
+ this.principal=principal;
+ if(principal==null) {
+ return;
+ } else if(principal instanceof BasicPrincipal) {
+ value = principal.getName() + ':' + app + ":BasicAuth:AS";
+ } else if(principal instanceof TrustPrincipal) {
+ TrustPrincipal tp = (TrustPrincipal)principal;
+ // recursive
+ init(tp.original(),app);
+ value += principal.getName() + ':' + app + ":Trust:AS" + ',' + tp.userChain();
+ } else if(principal instanceof TGuardPrincipal) {
+ value = principal.getName() + ':' + app + ":TGUARD:AS";
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return principal==null?"":principal.getName();
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/client/Delete.java b/client/src/main/java/com/att/cadi/client/Delete.java
new file mode 100644
index 0000000..9367d4d
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Delete.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+
+public class Delete<T> extends AAFClient.Call<T> {
+ public Delete(AAFClient ac, RosettaDF<T> df) {
+ super(ac,df);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Result<T> delete(final String pathInfo, final T t) throws Exception {
+ if(t==null) {
+ return (Result<T>)delete(pathInfo);
+ }
+ return client.hman.best(client.ss,
+ new Retryable<Result<T>>() {
+ @Override
+ public Result<T> code(Rcli<?> client) throws APIException, CadiException {
+ Future<T> ft = client.delete(pathInfo,df,t);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+
+ public Result<Void> delete(final String pathInfo) throws Exception {
+ return client.hman.best(client.ss,
+ new Retryable<Result<Void>>() {
+ @Override
+ public Result<Void> code(Rcli<?> client) throws APIException, CadiException {
+ Future<Void> ft = client.delete(pathInfo,VOID_CONTENT_TYPE);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+
+
+
+}
diff --git a/client/src/main/java/com/att/cadi/client/EClient.java b/client/src/main/java/com/att/cadi/client/EClient.java
new file mode 100644
index 0000000..f508029
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/EClient.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.rosetta.env.RosettaDF;
+
+
+public interface EClient<CT> {
+ public void setMethod(String meth);
+ public void setPathInfo(String pathinfo);
+ public void setPayload(Transfer transfer);
+ public void addHeader(String tag, String value);
+ public void setQueryParams(String q);
+ public void setFragment(String f);
+ public void send() throws APIException;
+ public<T> Future<T> futureCreate(Class<T> t);
+ public Future<String> futureReadString();
+ public<T> Future<T> futureRead(RosettaDF<T> df,Data.TYPE type);
+ public<T> Future<T> future(T t);
+ public Future<Void> future(HttpServletResponse resp, int expected) throws APIException;
+
+ public interface Transfer {
+ public void transfer(OutputStream os) throws IOException, APIException;
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/client/EnvAccess.java b/client/src/main/java/com/att/cadi/client/EnvAccess.java
new file mode 100644
index 0000000..f331c9a
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/EnvAccess.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import com.att.cadi.Access;
+import com.att.cadi.Symm;
+import com.att.inno.env.Decryptor;
+import com.att.inno.env.Env;
+import com.att.inno.env.impl.BasicEnv;
+
+public class EnvAccess implements Access {
+ private Env env;
+
+ /**
+ * String Property tag for files/resources that may contain properties. Can be null.
+ * Resources of ClassLoader will be checked first, if exist. Can be null.
+ * @param env
+ * @param tag
+ * @param cl
+ * @throws IOException
+ */
+ public EnvAccess(BasicEnv env, ClassLoader cl) throws IOException {
+ this.env = env;
+ final Symm s = Symm.obtain(this);
+ env.set(new Decryptor() {
+ private Symm symm = s;
+ @Override
+ public String decrypt(String encrypted) {
+ try {
+ return (encrypted!=null && (encrypted.startsWith(Symm.ENC)))
+ ? symm.depass(encrypted)
+ : encrypted;
+ } catch (IOException e) {
+ return "";
+ }
+ }
+ }
+ );
+ }
+
+
+ /**
+ * Construct with the Classloader of Env and CADI_PROP_FILES, if possible
+ *
+ * @param env
+ * @throws IOException
+ */
+ public EnvAccess(BasicEnv env) throws IOException {
+ this(env, env.getClass().getClassLoader());
+ }
+
+ @Override
+ public void log(Level level, Object... elements) {
+ switch(level) {
+ case AUDIT:
+ env.audit().log(elements);
+ break;
+ case DEBUG:
+ env.debug().log(elements);
+ break;
+ case ERROR:
+ env.error().log(elements);
+ break;
+ case INFO:
+ env.info().log(elements);
+ break;
+ case INIT:
+ env.init().log(elements);
+ break;
+ case WARN:
+ env.warn().log(elements);
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ @Override
+ public void log(Exception e, Object... elements) {
+ env.error().log(e,elements);
+ }
+
+ @Override
+ public void printf(Level level, String fmt, Object... elements) {
+ if(willLog(level)) {
+ log(level,String.format(fmt, elements));
+ }
+ }
+
+
+ @Override
+ public boolean willLog(Level level) {
+ switch(level) {
+ case AUDIT:
+ return env.audit().isLoggable();
+ case DEBUG:
+ return env.debug().isLoggable();
+ case ERROR:
+ return env.error().isLoggable();
+ case INFO:
+ return env.info().isLoggable();
+ case INIT:
+ return env.init().isLoggable();
+ case WARN:
+ return env.warn().isLoggable();
+ default:
+ return false;
+ }
+ }
+
+
+ @Override
+ public void setLogLevel(Level level) {
+ // unused
+ }
+
+ @Override
+ public ClassLoader classLoader() {
+ return env.getClass().getClassLoader();
+ }
+
+ @Override
+ public String getProperty(String string, String def) {
+ return env.getProperty(string, def);
+ }
+
+ @Override
+ public void load(InputStream is) throws IOException {
+ Properties props = new Properties();
+ props.load(is);
+ for(Entry<Object, Object> es :props.entrySet()) {
+ env.setProperty(es.getKey().toString(), es.getValue().toString());
+ }
+ }
+
+ @Override
+ public String decrypt(String encrypted, boolean anytext) throws IOException {
+ return env.decryptor().decrypt(encrypted);
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/client/Future.java b/client/src/main/java/com/att/cadi/client/Future.java
new file mode 100644
index 0000000..1752907
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Future.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+
+public abstract class Future<T> {
+ public T value;
+ public abstract boolean get(int timeout) throws CadiException;
+
+ public abstract int code();
+ public abstract String body();
+ public abstract String header(String tag);
+}
diff --git a/client/src/main/java/com/att/cadi/client/Get.java b/client/src/main/java/com/att/cadi/client/Get.java
new file mode 100644
index 0000000..d05654d
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Get.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+
+public class Get<T> extends AAFClient.Call<T> {
+ public Get(AAFClient ac, RosettaDF<T> df) {
+ super(ac,df);
+ }
+
+ public Result<T> read(final String pathInfo) throws Exception {
+ return client.hman.best(client.ss,
+ new Retryable<Result<T>>() {
+ @Override
+ public Result<T> code(Rcli<?> client) throws APIException, CadiException {
+ Future<T> ft = client.read(pathInfo,df);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/client/Holder.java b/client/src/main/java/com/att/cadi/client/Holder.java
new file mode 100644
index 0000000..93067f9
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Holder.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+/**
+ * Use to set Variables outside of Anonymous classes.
+ *
+ *
+ * @param <T>
+ */
+public class Holder<T> {
+ private T value;
+ public Holder(T t) {
+ value = t;
+ }
+ public void set(T t) {
+ value = t;
+ }
+
+ public T get() {
+ return value;
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/client/Post.java b/client/src/main/java/com/att/cadi/client/Post.java
new file mode 100644
index 0000000..7cc1b8c
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Post.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+
+public class Post<T> extends AAFClient.Call<T> {
+ public Post(AAFClient ac, RosettaDF<T> df) {
+ super(ac,df);
+ }
+
+ public Result<T> create(final String pathInfo, final T t) throws APIException, CadiException, LocatorException {
+ return client.hman.best(client.ss,
+ new Retryable<Result<T>>() {
+ @Override
+ public Result<T> code(Rcli<?> client) throws APIException, CadiException {
+ Future<T> ft = client.create(pathInfo,df,t);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/client/PropertyLocator.java b/client/src/main/java/com/att/cadi/client/PropertyLocator.java
new file mode 100644
index 0000000..37bc7b6
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/PropertyLocator.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Random;
+
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+
+public class PropertyLocator implements Locator {
+ private final URI [] orig;
+ private PLItem[] current;
+ private int end;
+ private final Random random;
+
+ /**
+ * comma delimited root url list
+ *
+ * @param locList
+ * @throws LocatorException
+ */
+ public PropertyLocator(String locList) throws LocatorException {
+ if(locList==null)throw new LocatorException("No Location List given for PropertyLocator");
+ String[] locarray = locList.split("\\s*,\\s*");
+ orig = new URI[locarray.length];
+
+ random = new Random();
+
+ for(int i=0;i<locarray.length;++i) {
+ try {
+ orig[i] = new URI(locarray[i]);
+ } catch (URISyntaxException e) {
+ throw new LocatorException(e);
+ }
+ }
+
+ current = new PLItem[orig.length];
+ refresh();
+ }
+
+ @Override
+ public URI get(Item item) throws LocatorException {
+ return orig[((PLItem)item).idx];
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return end>0?current[0]:null;
+ }
+
+ @Override
+ public boolean hasItems() {
+ return end>0;
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ int spot;
+ if((spot=(((PLItem)item).order+1))>=end)return null;
+ return current[spot];
+ }
+
+ @Override
+ public synchronized void invalidate(Item item) throws LocatorException {
+ if(--end<=0)return;
+ PLItem pli = (PLItem)item;
+ int i,order;
+ for(i=0;i<end;++i) {
+ if(pli==current[i])break;
+ }
+ order = current[i].order;
+ for(;i<end;++i) {
+ current[i]=current[i+1];
+ current[i].order=order++;
+ }
+ current[end]=pli;
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ switch(current.length) {
+ case 0:
+ return null;
+ case 1:
+ return current[0];
+ default:
+ return current[Math.abs(random.nextInt())%end];
+ }
+ }
+
+ @Override
+ public synchronized boolean refresh() {
+ end = orig.length;
+
+ // Build up list
+ for(int i = 0; i < end ; ++i) {
+ if(current[i]==null)current[i]=new PLItem(i);
+ else current[i].idx=current[i].order=i;
+ }
+ return true;
+ }
+
+ private class PLItem implements Item {
+ public int idx,order;
+
+ public PLItem(int i) {
+ idx = order =i;
+ }
+
+ public String toString() {
+ return "Item: " + idx + " order: " + order;
+ }
+ }
+
+ @Override
+ public void destroy() {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/client/Put.java b/client/src/main/java/com/att/cadi/client/Put.java
new file mode 100644
index 0000000..033216b
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Put.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import com.att.cadi.CadiException;
+import com.att.inno.env.APIException;
+import com.att.rosetta.env.RosettaDF;
+
+public class Put<T> extends AAFClient.Call<T> {
+ public Put(AAFClient ac, RosettaDF<T> df) {
+ super(ac,df);
+ }
+
+ public Result<T> update(final String pathInfo, final T t) throws Exception {
+ return client.hman.best(client.ss,
+ new Retryable<Result<T>>() {
+ @Override
+ public Result<T> code(Rcli<?> client) throws APIException, CadiException {
+ Future<T> ft = client.update(pathInfo,df,t);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+
+ public Result<Void> update(final String pathInfo) throws Exception {
+ return client.hman.best(client.ss,
+ new Retryable<Result<Void>>() {
+ @Override
+ public Result<Void> code(Rcli<?> client) throws APIException, CadiException {
+ Future<Void> ft = client.update(pathInfo);
+ if(ft.get(client.readTimeout)) {
+ return Result.ok(ft.code(),ft.value);
+ } else {
+ return Result.err(ft.code(),ft.body());
+ }
+ }
+ });
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/client/RawClient.java b/client/src/main/java/com/att/cadi/client/RawClient.java
new file mode 100644
index 0000000..d1a1fc2
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/RawClient.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.net.URI;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+
+public abstract class RawClient {
+ protected static String aafid, aafpass, aafurl;
+ protected static Symm symm;
+
+ protected static boolean init(PrintStream out) {
+ try {
+ String propfile = System.getProperty(Config.CADI_PROP_FILES);
+ if(propfile==null) {
+ propfile = "raw.props";
+ }
+ File pfile = new File(propfile);
+ if(!pfile.exists()) {
+ if(propfile.equals("raw.props")) {
+ out.println("Creating 'raw.props'. Edit for proper values, then run again. Alternatively, set "
+ + Config.CADI_PROP_FILES+" to a cadi properties file");
+ FileOutputStream fos = new FileOutputStream(pfile);
+ PrintStream ps = new PrintStream(fos);
+ try {
+ ps.println("# Use http://www.bing.com/maps to figure out LAT/LONG of an Address");
+ ps.println("AFT_LATITUDE=38.432930");
+ ps.println("AFT_LONGITUDE=-90.432480");
+ ps.println("AFT_ENVIRONMENT=AFTUAT");
+ ps.print(Config.AAF_URL);
+ ps.println("=aaf_url=https://DME2RESOLVE/service=com.att.authz.AuthorizationService/version=2.0/envContext=DEV/routeOffer=BAU_SE");
+ ps.print(Config.CADI_KEYFILE);
+ ps.println("=<keyfile. use java -jar cadi-core*.jar in lib dir>");
+ ps.println(Config.AAF_MECHID);
+ ps.print("=<your id>");
+ ps.println(Config.AAF_MECHPASS);
+ ps.print("=<your encrypted password. use java -jar cadi-core*.jar in lib dir>");
+ } finally {
+ ps.close();
+ }
+ }
+ } else {
+ FileInputStream fis = new FileInputStream(propfile);
+ try {
+ System.getProperties().load(fis);
+ } finally {
+ fis.close();
+ }
+
+ String cadiKeyFile = System.getProperty(Config.CADI_KEYFILE);
+ aafid = System.getProperty(Config.AAF_MECHID);
+ aafpass = System.getProperty(Config.AAF_MECHPASS);
+ aafurl = System.getProperty(Config.AAF_URL);
+ out.println("Contacting: " + aafurl);
+
+ if(cadiKeyFile==null || aafid==null || aafpass==null || aafurl==null ) {
+ out.print(Config.CADI_KEYFILE);
+ out.print(", ");
+ out.print(Config.CADI_KEYFILE);
+ out.print(", ");
+ out.print(Config.CADI_KEYFILE);
+ out.print(", ");
+ out.print(Config.CADI_KEYFILE);
+ out.print(" need to be set in ");
+ out.println(propfile);
+ } else {
+ fis = new FileInputStream(cadiKeyFile);
+ try {
+ symm = Symm.obtain(fis);
+ } finally {
+ fis.close();
+ }
+ }
+ return true;
+ }
+ } catch (Exception e) {
+ e.printStackTrace(out);
+ }
+ return false;
+
+ }
+
+ public abstract String call(final PrintStream out, final String meth, final String path) throws Exception;
+
+ public static void main(String[] args) {
+ // Sonar idiocy
+ PrintStream out = System.out;
+
+ try {
+ if(init(out)) {
+ if(args.length<2) {
+ System.out.println("Parameters: <Method> <path>");
+ } else {
+ RawClient client = new DME2();
+ out.println(client.call(out,args[0],args[1]));
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace(out);
+ }
+ }
+
+ protected static class DME2 extends RawClient {
+
+ public String call(final PrintStream out, final String meth, final String path) {
+ try {
+ DME2Client client = new DME2Client(new URI(aafurl),10000);
+ client.setCredentials(aafid, symm.depass(aafpass));
+ client.setMethod(meth);
+ client.setContext(path);
+
+ if("GET".equalsIgnoreCase(meth) ||
+ "DELETE".equalsIgnoreCase(meth)) {
+ client.setPayload("");
+ } else if("POST".equalsIgnoreCase(meth) ||
+ "PUT".equalsIgnoreCase(meth)) {
+ int c;
+ StringBuilder sb = new StringBuilder();
+ while((c=System.in.read()) >=0) {
+ sb.append((char)c);
+ }
+ client.setPayload(sb.toString());
+ }
+ return client.sendAndWait(10000);
+ } catch (Exception e) {
+ e.printStackTrace(out);
+ return "";
+ }
+ }
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/client/Rcli.java b/client/src/main/java/com/att/cadi/client/Rcli.java
new file mode 100644
index 0000000..f14645e
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Rcli.java
@@ -0,0 +1,697 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Enumeration;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Pool;
+import com.att.inno.env.util.Pool.Pooled;
+import com.att.rosetta.env.RosettaDF;
+
+public abstract class Rcli<CT> {
+ public static final String BLANK = "";
+ public static final String CONTENT_TYPE = "Content-Type";
+ public static final String ACCEPT = "Accept";
+
+ protected static final String POST = "POST";
+ protected static final String GET = "GET";
+ protected static final String PUT = "PUT";
+ protected static final String DELETE = "DELETE";
+ protected TYPE type;
+ protected String apiVersion;
+ protected int readTimeout = 5000;
+ protected int connectionTimeout = 3000;
+ protected URI uri;
+ private String queryParams, fragment;
+ public static Pool<byte[]> buffPool = new Pool<byte[]>(new Pool.Creator<byte[]>() {
+ @Override
+ public byte[] create() throws APIException {
+ return new byte[1024];
+ }
+
+ @Override
+ public void destroy(byte[] t) {
+ }
+
+ @Override
+ public boolean isValid(byte[] t) {
+ return true;
+ }
+
+ @Override
+ public void reuse(byte[] t) {
+ }
+ });
+
+
+ public Rcli() {
+ super();
+ }
+
+ public abstract void setSecuritySetter(SecuritySetter<CT> ss);
+ public abstract SecuritySetter<CT> getSecuritySetter();
+
+
+ public Rcli<CT> forUser(SecuritySetter<CT> ss) {
+ Rcli<CT> rv = clone(uri==null?this.uri:uri,ss);
+ setSecuritySetter(ss);
+ rv.type = type;
+ rv.apiVersion = apiVersion;
+ return rv;
+ }
+
+ protected abstract Rcli<CT> clone(URI uri, SecuritySetter<CT> ss);
+
+ public abstract void invalidate() throws CadiException;
+
+ public Rcli<CT> readTimeout(int millis) {
+ readTimeout = millis;
+ return this;
+ }
+
+ public Rcli<CT> connectionTimeout(int millis) {
+ connectionTimeout = millis;
+ return this;
+ }
+
+ public Rcli<CT> type(TYPE type) {
+ this.type=type;
+ return this;
+ }
+
+ public Rcli<CT> apiVersion(String apiVersion) {
+ this.apiVersion = apiVersion;
+ return this;
+ }
+
+ public boolean isApiVersion(String prospective) {
+ return apiVersion.equals(prospective);
+ }
+
+
+ public String typeString(Class<?> cls) {
+ return "application/"+cls.getSimpleName()+"+"+type.name().toLowerCase()+
+ (apiVersion==null?BLANK:";version="+apiVersion);
+ }
+
+ protected abstract EClient<CT> client() throws CadiException;
+
+
+ public<T> Future<T> create(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,contentType);
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(df.getTypeClass());
+ }
+
+ public<T> Future<T> create(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(df.getTypeClass());
+ }
+
+ public<T> Future<T> create(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,typeString(cls));
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(df.getTypeClass());
+ }
+
+ public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,typeString(cls));
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(cls);
+ }
+
+ public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(POST);
+ client.addHeader(CONTENT_TYPE,contentType);
+ client.setPathInfo(pathinfo);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureCreate(Void.class);
+ }
+
+
+ public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(GET);
+ client.addHeader(ACCEPT, accept);
+
+ for(int i=1;i<headers.length;i=i+2) {
+ client.addHeader(headers[i-1],headers[i]);
+ }
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+
+ client.setPathInfo(pathinfo);
+
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureReadString();
+ }
+
+ public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(GET);
+ client.addHeader(ACCEPT, accept);
+ for(int i=1;i<headers.length;i=i+2) {
+ client.addHeader(headers[i-1],headers[i]);
+ }
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureRead(df,type);
+ }
+
+ public<T> Future<T> read(String pathinfo, RosettaDF<T> df,String ... headers) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(GET);
+ client.addHeader(ACCEPT, typeString(df.getTypeClass()));
+ for(int i=1;i<headers.length;i=i+2) {
+ client.addHeader(headers[i-1],headers[i]);
+ }
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureRead(df,type);
+ }
+
+ public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(GET);
+ client.addHeader(ACCEPT, typeString(cls));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.futureRead(df,type);
+ }
+
+ public<T> Future<T> update(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE,contentType);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.futureReadString();
+ }
+
+
+ public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ public<T> Future<T> update(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE, typeString(cls));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ /**
+ * A method to update with a VOID
+ * @param pathinfo
+ * @param resp
+ * @param expected
+ * @return
+ * @throws APIException
+ * @throws CadiException
+ */
+ public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(PUT);
+ client.addHeader(CONTENT_TYPE, typeString(Void.class));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+// client.setPayload(new EClient.Transfer() {
+// @Override
+// public void transfer(OutputStream os) throws IOException, APIException {
+// }
+// });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(null);
+ }
+
+ public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, contentType);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ public<T> Future<T> delete(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, typeString(cls));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+ public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ df.newData().out(type).direct(t,os);
+ }
+ });
+
+ client.send();
+ queryParams = fragment = null;
+ return client.future(t);
+ }
+
+
+ public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, typeString(cls));
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.future((T)null);
+ }
+
+ public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {
+ final int idx = pathinfo.indexOf('?');
+ final String qp;
+ if(idx>=0) {
+ qp=pathinfo.substring(idx+1);
+ pathinfo=pathinfo.substring(0,idx);
+ } else {
+ qp=queryParams;
+ }
+
+ EClient<CT> client = client();
+ client.setMethod(DELETE);
+ client.addHeader(CONTENT_TYPE, contentType);
+ client.setQueryParams(qp);
+ client.setFragment(fragment);
+ client.setPathInfo(pathinfo);
+ client.setPayload(null);
+ client.send();
+ queryParams = fragment = null;
+ return client.future(null);
+ }
+
+ public Future<Void> transfer(final HttpServletRequest req, final HttpServletResponse resp, final String pathParam, final int expected) throws CadiException, APIException {
+ EClient<CT> client = client();
+ URI uri;
+ try {
+ uri = new URI(req.getRequestURI());
+ } catch (Exception e) {
+ throw new CadiException("Invalid incoming URI",e);
+ }
+ String name;
+ for(Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {
+ name = en.nextElement();
+ client.addHeader(name,req.getHeader(name));
+ }
+ client.setQueryParams(req.getQueryString());
+ client.setFragment(uri.getFragment());
+ client.setPathInfo(pathParam);
+ String meth = req.getMethod();
+ client.setMethod(meth);
+ if(!"GET".equals(meth)) {
+ client.setPayload(new EClient.Transfer() {
+ @Override
+ public void transfer(OutputStream os) throws IOException, APIException {
+ final ServletInputStream is = req.getInputStream();
+ int read;
+ // reuse Buffers
+ Pooled<byte[]> pbuff = buffPool.get();
+ try {
+ while((read=is.read(pbuff.content))>=0) {
+ os.write(pbuff.content,0,read);
+ }
+ } finally {
+ pbuff.done();
+ }
+ }
+ });
+ }
+ client.send();
+ return client.future(resp, expected);
+ }
+
+ public String toString() {
+ return uri.toString();
+ }
+
+ /**
+ * @param queryParams the queryParams to set
+ * @return
+ */
+ public Rcli<CT> setQueryParams(String queryParams) {
+ this.queryParams = queryParams;
+ return this;
+ }
+
+
+ /**
+ * @param fragment the fragment to set
+ * @return
+ */
+ public Rcli<CT> setFragment(String fragment) {
+ this.fragment = fragment;
+ return this;
+ }
+
+ public URI getURI() {
+ return uri;
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/client/Result.java b/client/src/main/java/com/att/cadi/client/Result.java
new file mode 100644
index 0000000..1e4909e
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Result.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+public class Result<T> {
+ public final int code;
+ public final T value;
+ public final String error;
+
+ private Result(int code, T value, String error) {
+ this.code = code;
+ this.value = value;
+ this.error = error;
+ }
+
+ public static<T> Result<T> ok(int code,T t) {
+ return new Result<T>(code,t,null);
+ }
+
+ public static<T> Result<T> err(int code,String body) {
+ return new Result<T>(code,null,body);
+ }
+
+ public boolean isOK() {
+ return error==null;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Code: ");
+ sb.append(code);
+ if(error!=null) {
+ sb.append(" = ");
+ sb.append(error);
+ }
+ return sb.toString();
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/client/Retryable.java b/client/src/main/java/com/att/cadi/client/Retryable.java
new file mode 100644
index 0000000..e276837
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/client/Retryable.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.client;
+
+import java.net.ConnectException;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.inno.env.APIException;
+
+/**
+ *
+ *
+ * @param <RT>
+ * @param <RET>
+ */
+public abstract class Retryable<RET> {
+ // be able to hold state for consistent Connections. Not required for all connection types.
+ public Rcli<?> lastClient;
+ private Locator.Item item;
+
+ public Retryable() {
+ lastClient = null;
+ item = null;
+ }
+
+ public Retryable(Retryable<?> ret) {
+ lastClient = ret.lastClient;
+ item = ret.item;
+ }
+
+ public Locator.Item item(Locator.Item item) {
+ lastClient = null;
+ this.item = item;
+ return item;
+ }
+ public Locator.Item item() {
+ return item;
+ }
+
+ public abstract RET code(Rcli<?> client) throws CadiException, ConnectException, APIException;
+
+ /**
+ * Note, Retryable is tightly coupled to the Client Utilizing. It will not be the wrong type.
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ public <CLIENT> Rcli<CLIENT> lastClient() {
+ return (Rcli<CLIENT>)lastClient;
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/dme2/DEClient.java b/client/src/main/java/com/att/cadi/dme2/DEClient.java
new file mode 100644
index 0000000..6810916
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DEClient.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URI;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.aft.dme2.handler.DME2RestfulHandler;
+import com.att.aft.dme2.handler.DME2RestfulHandler.ResponseInfo;
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.EClient;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.rosetta.env.RosettaDF;
+
+public class DEClient implements EClient<DME2Client> {
+ private DME2Client client;
+ private DME2RestfulHandler replyHandler;
+ private EClient.Transfer payload;
+ private boolean isProxy;
+ private SecuritySetter<DME2Client> ss;
+
+ public DEClient(DME2Manager manager, SecuritySetter<DME2Client> ss, URI uri, long timeout) throws DME2Exception, CadiException {
+ client = new DME2Client(manager,uri,timeout);
+ client.setAllowAllHttpReturnCodes(true);
+ this.ss = ss;
+ ss.setSecurity(client);
+ replyHandler = new DME2RestfulHandler(Rcli.BLANK);
+ client.setReplyHandler(replyHandler);
+ }
+
+ @Override
+ public void setMethod(String meth) {
+ client.setMethod(meth);
+ }
+
+ /**
+ * DME2 can't handle having QueryParams on the URL line, but it is the most natural way, so...
+ *
+ * Also, DME2 can't handle "/proxy" as part of Context in the main URI line, so we add it when we see authz-gw to "isProxy"
+ */
+ public void setPathInfo(String pathinfo) {
+ int qp = pathinfo.indexOf('?');
+ if(qp<0) {
+ client.setContext(isProxy?("/proxy"+pathinfo):pathinfo);
+ } else {
+ client.setContext(isProxy?("/proxy"+pathinfo.substring(0,qp)):pathinfo.substring(0,qp));
+ client.setQueryParams(pathinfo.substring(qp+1));
+ }
+ }
+
+ @Override
+ public void setPayload(EClient.Transfer transfer) {
+ payload = transfer;
+ }
+
+ @Override
+ public void addHeader(String tag, String value) {
+ client.addHeader(tag, value);
+ }
+
+
+ @Override
+ public void setQueryParams(String q) {
+ client.setQueryParams(q);
+ }
+
+ @Override
+ public void setFragment(String f) {
+ // DME2 does not implement this
+ }
+
+ @Override
+ public void send() throws APIException {
+ try {
+ if(payload!=null) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ payload.transfer(baos);
+ client.setPayload(new String(baos.toByteArray()));
+ } else {
+ client.setPayload("");
+ }
+ client.send();
+ } catch (DME2Exception e) {
+ throw new APIException(e);
+ } catch (IOException e) {
+ throw new APIException(e);
+ }
+ }
+
+
+ public class DFuture<T> extends Future<T> {
+ protected final DME2RestfulHandler reply;
+ protected ResponseInfo info;
+
+ public DFuture(DME2RestfulHandler reply) {
+ this.reply = reply;
+ }
+
+ protected boolean evalInfo() throws APIException{
+ //return info.getCode()==200;
+ return true;
+ };
+
+ public final boolean get(int timeout) throws CadiException {
+ try {
+ info = reply.getResponse(timeout);
+ ss.setLastResponse(info.getCode());
+ return evalInfo();
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ @Override
+ public int code() {
+ return info.getCode();
+ }
+
+ @Override
+ public String body() {
+ return info.getBody();
+ }
+
+ @Override
+ public String header(String tag) {
+ return info.header(tag);
+ }
+
+ }
+
+ @Override
+ public <T> Future<T> futureCreate(Class<T> t) {
+ return new DFuture<T>(replyHandler) {
+ public boolean evalInfo() throws APIException {
+
+ return info.getCode()==201;
+ }
+ };
+ }
+
+
+ @Override
+ public Future<String> futureReadString() {
+ return new DFuture<String>(replyHandler) {
+ public boolean evalInfo() throws APIException {
+ if(info.getCode()==200) {
+ value = info.getBody();
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ @Override
+ public<T> Future<T> futureRead(final RosettaDF<T> df, final Data.TYPE type) {
+ return new DFuture<T>(replyHandler) {
+ public boolean evalInfo() throws APIException {
+ if(info.getCode()==200) {
+ value = df.newData().in(type).load(info.getBody()).asObject();
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ @Override
+ public <T> Future<T> future(final T t) {
+ return new DFuture<T>(replyHandler) {
+ public boolean evalInfo() {
+ if(info.getCode()==200) {
+ value = t;
+ return true;
+ }
+ return false;
+ }
+ };
+ }
+
+ @Override
+ public Future<Void> future(HttpServletResponse resp,int expected) throws APIException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public void setProxy(boolean isProxy) {
+ this.isProxy=isProxy;
+ }
+
+
+}
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java b/client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java
new file mode 100644
index 0000000..988c92f
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2BasicAuth.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.Access;
+import com.att.cadi.CadiException;
+import com.att.cadi.client.AbsBasicAuth;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.principal.BasicPrincipal;
+
+public class DME2BasicAuth extends AbsBasicAuth<DME2Client> {
+ public DME2BasicAuth(String user, String pass, SecurityInfoC<DME2Client> si) throws IOException {
+ super(user,pass,si);
+ }
+
+ public DME2BasicAuth(Access access, SecurityInfoC<DME2Client> si) throws IOException {
+ super(access.getProperty(Config.AAF_MECHID, null),
+ access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),
+ si);
+ }
+
+ public DME2BasicAuth(BasicPrincipal bp,SecurityInfoC<DME2Client> si) throws IOException {
+ super(bp.getName(),new String(bp.getCred()),si);
+ }
+
+ public DME2BasicAuth(Access access) throws IOException, GeneralSecurityException {
+ super(access.getProperty(Config.AAF_MECHID, null),
+ access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),
+ new SecurityInfoC<DME2Client>(access));
+ }
+
+ public void setSecurity(DME2Client client) throws CadiException {
+ if(isDenied()) {
+ throw new CadiException(REPEAT_OFFENDER);
+ }
+ client.addHeader("Authorization", headValue);
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java b/client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java
new file mode 100644
index 0000000..f64367b
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2ClientSS.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.IOException;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.SecuritySetter;
+
+public class DME2ClientSS implements SecuritySetter<DME2Client> {
+ private Access access;
+ private String user,crd;
+
+ public DME2ClientSS(Access access, String user, String pass) throws IOException {
+ this.access = access;
+ this.user = user;
+ this.crd = pass;
+ }
+
+ @Override
+ public void setSecurity(DME2Client client) {
+ try {
+ client.setCredentials(user, access.decrypt(crd, false));
+ } catch (IOException e) {
+ access.log(Level.ERROR,e,"Error decrypting DME2 Password");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return user;
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2Locator.java b/client/src/main/java/com/att/cadi/dme2/DME2Locator.java
new file mode 100644
index 0000000..b81cf4a
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2Locator.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Random;
+
+//
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.aft.dme2.api.DME2Server;
+import com.att.aft.dme2.manager.registry.DME2Endpoint;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+
+public class DME2Locator implements Locator {
+ private DME2Manager dm;
+ private DME2Endpoint[] endpoints;
+ private Access access;
+ private String service;
+ private String version;
+ private String routeOffer;
+ private String envContext;
+ private String thisMachine;
+ private String pathInfo;
+ private int thisPort;
+ private boolean removeSelf;
+ private final static Random random = new Random();
+
+ // Default is to not bother trying to remove self
+ public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer) throws DME2Exception, UnknownHostException, LocatorException {
+ this(access,dm,service,version,envContext,routeOffer,false);
+ }
+
+ public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {
+ this.access = access;
+ if(dm==null) {
+ this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());
+ } else {
+ this.dm = dm;
+ }
+ this.service = service;
+ this.version = version;
+ this.envContext = envContext;
+ this.routeOffer = routeOffer;
+ refresh();
+ DME2Server server = dm.getServer();
+ if(server == null) {
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ try {
+ thisMachine = server.getServerProperties().getHostname();
+ //thisPort = server.getPort();
+ thisPort = server.getServerProperties().getPort();
+ } catch(NullPointerException np) { // BAD BOY, DME2...
+ access.log(Level.ERROR, "WARNING: DME2 threw a NullPointer Exception getting Server Machine and Port");
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ }
+ }
+ this.removeSelf = removeSelf;
+ }
+
+ // Default is to not bother trying to remove self
+ public DME2Locator(Access access, DME2Manager dm, String aafurl) throws DME2Exception, UnknownHostException, LocatorException {
+ this(access,dm,aafurl,false);
+ }
+
+ public DME2Locator(Access access, DME2Manager dm, String aafurl, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {
+ if(aafurl==null) throw new LocatorException("URL is null");
+ this.access = access;
+ if(dm==null) {
+ dm = this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());
+ } else {
+ this.dm = dm;
+ }
+ String[] split = aafurl.split("/");
+ StringBuilder sb = new StringBuilder();
+ boolean dme2Entered = false;
+ for(String s : split) {
+ if(s.startsWith( "service=")) this.service = s.substring(8);
+ else if(s.startsWith("version=")) this.version = s.substring(8);
+ else if(s.startsWith("envContext=")) this.envContext = s.substring(11);
+ else if(s.startsWith("routeOffer=")) {
+ this.routeOffer = s.substring(11);
+ dme2Entered = true;
+ }
+ else if(dme2Entered) {
+ sb.append('/');
+ sb.append(s);
+ }
+ pathInfo = sb.toString();
+ }
+ DME2Server server = dm.getServer();
+ if(server == null) {
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ thisMachine = server.getServerProperties().getHostname();
+ if(thisMachine==null) { // even if server !=null, apparently, it can be uninitialized
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ try {
+ thisPort = server.getServerProperties().getPort();
+ } catch (Exception e) {
+ thisPort = 0;
+ }
+ }
+ }
+ this.removeSelf=removeSelf;
+ refresh();
+ }
+
+ @Override
+ public boolean refresh() {
+ try {
+ dm.refresh();
+ endpoints = dm.findEndpoints(service, version, envContext, routeOffer, true);
+ if(removeSelf) {
+ for(int i=0;i<endpoints.length;++i) {
+ if(endpoints[i].getPort()==thisPort && endpoints[i].getHost().equals(thisMachine))
+ endpoints[i]=null;
+ }
+ }
+ return endpoints.length!=0;
+ } catch (Exception e) {
+ access.log(Level.ERROR, e.getMessage());
+ }
+ return false;
+ }
+
+ private String noEndpointsString() {
+ StringBuilder sb = new StringBuilder("No DME2 Endpoints found for ");
+ sb.append(service);
+ sb.append('/');
+ sb.append(version);
+ sb.append('/');
+ sb.append(envContext);
+ sb.append('/');
+ sb.append(routeOffer);
+ return sb.toString();
+ }
+
+ @Override
+ public URI get(Locator.Item item) throws LocatorException {
+ if(!hasItems())
+ throw new LocatorException(noEndpointsString());
+ if(item == null)
+ return null;
+
+ Item li = ((Item)item);
+ // if URI has been created, use it
+ if(li.uri!=null)return li.uri;
+
+ // URI not created, create it
+ if(li.idx<endpoints.length) {
+ DME2Endpoint de = endpoints[li.idx];
+ if(de!=null) {
+ try {
+ return li.uri=new URI(de.getProtocol(),null,de.getHost(),de.getPort(),pathInfo,null,null);
+ } catch (URISyntaxException e) {
+ throw new LocatorException(e);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasItems() {
+ return endpoints!=null && endpoints.length>0;
+ }
+
+ @Override
+ public void invalidate(Locator.Item item) throws LocatorException {
+ if(item instanceof Item) {
+ int idx = ((Item)item).idx;
+ if(idx<endpoints.length) {
+ DME2Endpoint uhoh = endpoints[idx]; // Sometimes, DME2Endpoint, at least on File system, returns bogus entries.
+ endpoints[idx]=null;
+ boolean noneLeft=true;
+ for(int i=0;i<endpoints.length && noneLeft;++i) {
+ noneLeft = endpoints[i]==null;
+ }
+ if(noneLeft && refresh()) { // make sure DME2 isn't giving us the same invalidated entry...
+ for(int i=0;i<endpoints.length && noneLeft;++i) {
+ DME2Endpoint ep = endpoints[i];
+ if(ep != null &&
+ ep.getHost().equals(uhoh.getHost()) &&
+ ep.getPort()==uhoh.getPort()) {
+ endpoints[i]=null;
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ public class Item implements Locator.Item {
+ private final int idx;
+ private URI uri;
+ private Item(int i) {
+ idx = i;
+ uri = null;
+ }
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ if(!hasItems()) // checks endpoints
+ if(!refresh()) throw new LocatorException("No DME2 Endpoints Available");
+
+ // Some endpoints in Array are null. Need sub array of usable endpoints
+ int usable[] = new int[endpoints.length];
+ int count=0;
+ for(int i=0;i<endpoints.length;++i) {
+ if(endpoints[i]!=null) {
+ usable[count++] = i;
+ }
+ }
+ switch(count) {
+ case 0: refresh(); return null;
+ case 1: return new Item(usable[0]);
+ default:
+ int samemach[] = new int[count];
+ int samecount = 0,closecount=0;
+ // has to be sortable
+ Integer closemach[] = new Integer[count];
+
+ // Analyze for Same Machine or Remote machines
+ for(int i=0;i<count;++i) {
+ DME2Endpoint ep = endpoints[usable[i]];
+ String host = ep.getHost();
+ if(thisMachine.equalsIgnoreCase(host)) {
+ samemach[samecount++] = usable[i];
+ } else {
+ closemach[closecount++] = usable[i];
+ }
+ }
+
+ switch(samecount) {
+ case 0: break;
+ case 1: return new Item(samemach[0]);
+ default: // return randomized is multiple Endpoints on local machine.
+ int i = random.nextInt();
+ return new Item(usable[Math.abs(i%samecount)]);
+ }
+
+ // Analyze for closest remote
+ switch(closecount) {
+ case 0: return null;
+ case 1: return new Item(closemach[0]);
+ default: // return closest machine
+ DoubIndex remote[] = new DoubIndex[closecount];
+ int remotecount = 0;
+ for(int i=0;i<closecount;++i) {
+ DME2Endpoint de = endpoints[usable[i]];
+ remote[remotecount++] = new DoubIndex(de.getDistance(),i);
+ }
+ Arrays.sort(remote,new Comparator<DoubIndex> () {
+ @Override
+ public int compare(DoubIndex a, DoubIndex b) {
+ if(a.d<b.d) return -1;
+ if(a.d>b.d) return 1;
+ return (random.nextInt()%1)==0?1:0;// randomize if the same
+ }
+
+ });
+ return new Item(remote[0].idx);
+ }
+ }
+ }
+
+ private class DoubIndex {
+ public final double d;
+ public final int idx;
+
+ public DoubIndex(double doub, int i) {
+ d = doub;
+ idx = i;
+ }
+ }
+ @Override
+ public Item first() {
+ if(endpoints==null)return null;
+ for(int i=0;i<endpoints.length;++i) {
+ if(endpoints[i]!=null)
+ return new Item(i);
+ }
+ return null;
+ }
+
+ @Override
+ public Item next(Locator.Item item) throws LocatorException {
+ if(endpoints==null || endpoints.length==0 || !(item instanceof Item))return null;
+ int idx = ((Item)item).idx +1;
+ for(int i=idx;i<endpoints.length;++i) {
+ if(endpoints[i]!=null)
+ return new Item(i);
+ }
+// This is a mistake.. will start infinite loops
+// // Did not have any at end... try beginning
+// for(int i=0;i<idx-1;++i) {
+// if(endpoints[i]!=null)
+// return new Item(i);
+// }
+// // If still nothing, refresh
+// refresh();
+ return null;
+ }
+
+ @Override
+ public void destroy() {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java b/client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java
new file mode 100644
index 0000000..d4612f1
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2TransferSS.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.IOException;
+import java.security.Principal;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.CadiException;
+import com.att.cadi.client.AbsTransferSS;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+
+public class DME2TransferSS extends AbsTransferSS<DME2Client> {
+
+ public DME2TransferSS(Principal principal, String app, SecurityInfoC<DME2Client> si) throws IOException {
+ super(principal, app, si);
+ }
+
+ @Override
+ public void setSecurity(DME2Client client) throws CadiException {
+ if(value!=null) {
+ if(defSS==null) {
+ throw new CadiException("Need App Credentials to send message");
+ }
+ defSS.setSecurity(client);
+ client.addHeader(Config.CADI_USER_CHAIN, value);
+ }
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/dme2/DME2x509SS.java b/client/src/main/java/com/att/cadi/dme2/DME2x509SS.java
new file mode 100644
index 0000000..f60f791
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DME2x509SS.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.io.IOException;
+import java.security.cert.CertificateEncodingException;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.inno.env.APIException;
+
+
+public class DME2x509SS implements SecuritySetter<DME2Client> {
+ private String alias;
+
+ public DME2x509SS(final String sendAlias, SecurityInfoC<DME2Client> si) throws APIException, IOException, CertificateEncodingException {
+ if((alias=sendAlias) == null) {
+ if(si.default_alias == null) {
+ throw new APIException("JKS Alias is required to use X509SS Security. Use " + Config.CADI_ALIAS +" to set default alias");
+ } else {
+ alias = si.default_alias;
+ }
+ }
+ }
+
+ @Override
+ public void setSecurity(DME2Client dme2) throws CadiException {
+ // DME2Client has to have properties set before creation to work.
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return alias;
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/dme2/DRcli.java b/client/src/main/java/com/att/cadi/dme2/DRcli.java
new file mode 100644
index 0000000..9ff56ca
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dme2/DRcli.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dme2;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.att.aft.dme2.api.DME2Client;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.aft.dme2.manager.registry.DME2Endpoint;
+import com.att.aft.dme2.request.DmeUniformResource;
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.EClient;
+import com.att.cadi.client.Rcli;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+
+/**
+ * DME2 Rosetta Client
+ *
+ * JAXB defined JSON or XML over DME2 middleware
+ *
+ *
+ * @param <T>
+ */
+public class DRcli extends Rcli<DME2Client> {
+ // Can be more efficient if tied to manager, apparently. Can pass in null.
+ DME2Manager manager=null;
+ private SecuritySetter<DME2Client> ss;
+ private boolean isProxy;
+
+ public DRcli(URI uri, SecuritySetter<DME2Client> secSet) {
+ this.uri = uri;
+ type = TYPE.JSON;
+ apiVersion = null;
+ ss=secSet;
+ }
+
+ @Override
+ protected DRcli clone(URI uri, SecuritySetter<DME2Client> ss) {
+ return new DRcli(uri,ss);
+ }
+
+
+
+ /**
+ * Note from Thaniga on 11/5. DME2Client is not expected to be reused... need a fresh one
+ * on each transaction, which is expected to cover the Async aspects.
+ *
+ * @return
+ * @throws APIException
+ * @throws DME2Exception
+ */
+ protected EClient<DME2Client> client() throws CadiException {
+ try {
+ DEClient dc = new DEClient(manager,getSecuritySetter(),uri,readTimeout);
+ dc.setProxy(isProxy);
+ return dc;
+ } catch (DME2Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ public DRcli setManager(DME2Manager dme2Manager) {
+ manager = dme2Manager;
+ return this;
+ }
+
+ public List<DRcli> all() throws DME2Exception, APIException {
+ ArrayList<DRcli> al = new ArrayList<DRcli>();
+
+ if(manager == null) {
+ manager = DME2Manager.getDefaultInstance();
+ }
+ try {
+ DME2Endpoint[] endp = manager.getEndpoints(new DmeUniformResource(manager.getConfig(),uri));
+ // Convert Searchable Endpoints to Direct Endpoints
+ for(DME2Endpoint de : endp) {
+ al.add(new DRcli(
+ new URI(uri.getScheme(),null,de.getHost(),de.getPort(),null,null,null),ss)
+// new URI(uri.getScheme(),null,de.getHost(),de.getPort(),uri.getPath(),null,null),ss)
+ .setManager(manager)
+ );
+ }
+ } catch (MalformedURLException e) {
+ throw new APIException("Invalid URL",e);
+ } catch (URISyntaxException e) {
+ throw new APIException("Invalid URI",e);
+ }
+ return al;
+ }
+
+ @Override
+ public void invalidate() throws CadiException {
+ try {
+ manager.refresh();
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ @Override
+ public void setSecuritySetter(SecuritySetter<DME2Client> ss) {
+ this.ss = ss;
+ }
+
+ @Override
+ public SecuritySetter<DME2Client> getSecuritySetter() {
+ return ss;
+ }
+
+ public void setProxy(boolean isProxy) {
+ this.isProxy = isProxy;
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java b/client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java
new file mode 100644
index 0000000..498b013
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/dnsloc/DNSLocator.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.dnsloc;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+
+public class DNSLocator implements Locator {
+ private static enum Status {UNTRIED, OK, INVALID, SLOW};
+ private static final int CHECK_TIME = 3000;
+
+ private String host, protocol;
+ private Access access;
+ private Host[] hosts;
+ private int startPort, endPort;
+ private String suffix;
+
+ public DNSLocator(Access access, String protocol, String host, String range) {
+ this.host = host;
+ this.protocol = protocol;
+ this.access = access;
+ int dash = range.indexOf('-');
+ if(dash<0) {
+ startPort = endPort = Integer.parseInt(range);
+ } else {
+ startPort = Integer.parseInt(range.substring(0,dash));
+ endPort = Integer.parseInt(range.substring(dash + 1));
+ }
+ refresh();
+ }
+
+ @Override
+ public URI get(Item item) throws LocatorException {
+ return hosts[((DLItem)item).cnt].uri;
+ }
+
+ @Override
+ public boolean hasItems() {
+ for(Host h : hosts) {
+ if(h.status==Status.OK) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void invalidate(Item item) {
+ DLItem di = (DLItem)item;
+ hosts[di.cnt].status = Status.INVALID;
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ // not a good "best"
+ for(int i=0;i<hosts.length;++i) {
+ switch(hosts[i].status) {
+ case OK:
+ return new DLItem(i);
+ case INVALID:
+ break;
+ case SLOW:
+ break;
+ case UNTRIED:
+ try {
+ if(hosts[i].ia.isReachable(CHECK_TIME)) {
+ hosts[i].status = Status.OK;
+ return new DLItem(i);
+ }
+ } catch (IOException e) {
+ throw new LocatorException(e);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ throw new LocatorException("No Available URIs for " + host);
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return new DLItem(0);
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ DLItem di = (DLItem)item;
+ if(++di.cnt<hosts.length) {
+ return di;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean refresh() {
+ try {
+ InetAddress[] ias = InetAddress.getAllByName(host);
+ Host[] temp = new Host[ias.length * (1 + endPort - startPort)];
+ int cnt = -1;
+ for(int j=startPort; j<=endPort; ++j) {
+ for(int i=0;i<ias.length;++i) {
+ temp[++cnt] = new Host(ias[i], j, suffix);
+ }
+ }
+ hosts = temp;
+ return true;
+ } catch (Exception e) {
+ access.log(Level.ERROR, e);
+ }
+ return false;
+ }
+
+ private class Host {
+ private URI uri;
+ private InetAddress ia;
+ private Status status;
+
+ public Host(InetAddress inetAddress, int port, String suffix) throws URISyntaxException {
+ ia = inetAddress;
+ uri = new URI(protocol,null,inetAddress.getHostAddress(),port,suffix,null,null);
+ status = Status.UNTRIED;
+ }
+ }
+
+ private class DLItem implements Item {
+ public DLItem(int i) {
+ cnt = i;
+ }
+
+ private int cnt;
+ }
+
+ @Override
+ public void destroy() {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/http/HBasicAuthSS.java b/client/src/main/java/com/att/cadi/http/HBasicAuthSS.java
new file mode 100644
index 0000000..8d8826e
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HBasicAuthSS.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import com.att.cadi.Access;
+import com.att.cadi.CadiException;
+import com.att.cadi.client.AbsBasicAuth;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.cadi.principal.BasicPrincipal;
+
+public class HBasicAuthSS extends AbsBasicAuth<HttpURLConnection> {
+ public HBasicAuthSS(Access access, SecurityInfoC<HttpURLConnection> si) throws IOException {
+ super(access.getProperty(Config.AAF_MECHID, null),
+ access.decrypt(access.getProperty(Config.AAF_MECHPASS, null), false),
+ si);
+ }
+
+ public HBasicAuthSS(String user, String pass, SecurityInfoC<HttpURLConnection> si) throws IOException {
+ super(user,pass,si);
+ }
+
+ public HBasicAuthSS(String user, String pass, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws IOException {
+ super(user,pass,si);
+ if(asDefault) {
+ si.set(this);
+ }
+ }
+
+ public HBasicAuthSS(BasicPrincipal bp, SecurityInfoC<HttpURLConnection> si) throws IOException {
+ super(bp.getName(),new String(bp.getCred()),si);
+ }
+
+ public HBasicAuthSS(BasicPrincipal bp, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws IOException {
+ super(bp.getName(),new String(bp.getCred()),si);
+ if(asDefault) {
+ si.set(this);
+ }
+ }
+
+ @Override
+ public void setSecurity(HttpURLConnection huc) throws CadiException {
+ if(isDenied()) {
+ throw new CadiException(REPEAT_OFFENDER);
+ }
+ huc.addRequestProperty("Authorization" , headValue);
+ if(securityInfo!=null && huc instanceof HttpsURLConnection) {
+ securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);
+ }
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/http/HClient.java b/client/src/main/java/com/att/cadi/http/HClient.java
new file mode 100644
index 0000000..d17dcc7
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HClient.java
@@ -0,0 +1,434 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.EClient;
+import com.att.cadi.client.Future;
+import com.att.cadi.client.Rcli;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data;
+import com.att.inno.env.Data.TYPE;
+import com.att.inno.env.util.Pool.Pooled;
+import com.att.rosetta.env.RosettaDF;
+
+/**
+ * Low Level Http Client Mechanism. Chances are, you want the high level "HRcli"
+ * for Rosetta Object Translation
+ *
+ *
+ */
+public class HClient implements EClient<HttpURLConnection> {
+ private URI uri;
+ private ArrayList<Header> headers;
+ private String meth;
+ private String pathinfo;
+ private String query;
+ private String fragment;
+ private Transfer transfer;
+ private SecuritySetter<HttpURLConnection> ss;
+ private HttpURLConnection huc;
+ private int connectTimeout;
+
+ public HClient(SecuritySetter<HttpURLConnection> ss, URI uri,int connectTimeout) throws LocatorException {
+ if (uri == null) {
+ throw new LocatorException("No Service available to call");
+ }
+ this.uri = uri;
+ this.ss = ss;
+ this.connectTimeout = connectTimeout;
+ pathinfo = query = fragment = "";
+ }
+
+ @Override
+ public void setMethod(String meth) {
+ this.meth = meth;
+ }
+
+ @Override
+ public void setPathInfo(String pathinfo) {
+ this.pathinfo = pathinfo;
+ }
+
+ @Override
+ public void setPayload(Transfer transfer) {
+ this.transfer = transfer;
+ }
+
+ @Override
+ public void addHeader(String tag, String value) {
+ if (headers == null)
+ headers = new ArrayList<Header>();
+ headers.add(new Header(tag, value));
+ }
+
+ @Override
+ public void setQueryParams(String q) {
+ query = q;
+ }
+
+ @Override
+ public void setFragment(String f) {
+ fragment = f;
+ }
+
+ @Override
+ public void send() throws APIException {
+ try {
+ // Build URL from given URI plus current Settings
+ if(uri.getPath()==null) {
+ throw new APIException("Invalid URL entered for HClient");
+ }
+ StringBuilder pi = new StringBuilder(uri.getPath());
+ if(!pathinfo.startsWith("/")) {
+ pi.append('/');
+ }
+ pi.append(pathinfo);
+ URL url = new URI(
+ uri.getScheme(),
+ uri.getUserInfo(),
+ uri.getHost(),
+ uri.getPort(),
+ pi.toString(),
+ query,
+ fragment).toURL();
+ pathinfo=null;
+ query=null;
+ fragment=null;
+ huc = (HttpURLConnection) url.openConnection();
+ if(ss!=null) {
+ ss.setSecurity(huc);
+ }
+ huc.setRequestMethod(meth);
+ if (headers != null)
+ for (Header d : headers) {
+ huc.addRequestProperty(d.tag, d.value);
+ }
+ huc.setDoInput(true);
+ huc.setDoOutput(true);
+ huc.setUseCaches(false);
+ huc.setConnectTimeout(connectTimeout);
+ huc.connect();
+ if (transfer != null) {
+ transfer.transfer(huc.getOutputStream());
+ }
+ // TODO other settings? There's a bunch here.
+ } catch (Exception e) {
+ throw new APIException(e);
+ } finally { // ensure all these are reset after sends
+ meth=pathinfo=null;
+ if(headers!=null) {
+ headers.clear();
+ }
+ pathinfo = query = fragment = "";
+ }
+ }
+
+ public abstract class HFuture<T> extends Future<T> {
+ protected HttpURLConnection huc;
+ protected int respCode;
+ protected String respMessage;
+ protected IOException exception;
+ protected StringBuilder errContent;
+
+ public HFuture(final HttpURLConnection huc) {
+ this.huc = huc;
+ }
+
+ protected boolean evalInfo(HttpURLConnection huc) throws APIException, IOException{
+ return respCode == 200;
+ };
+
+ @Override
+ public final boolean get(int timeout) throws CadiException {
+ try {
+ huc.setReadTimeout(timeout);
+ respCode = huc.getResponseCode();
+ ss.setLastResponse(respCode);
+ if(evalInfo(huc)) {
+ return true;
+ } else {
+ extractError();
+ return false;
+ }
+ } catch (IOException | APIException e) {
+ throw new CadiException(e);
+ } finally {
+ close();
+ }
+ }
+
+ private void extractError() {
+ InputStream is = huc.getErrorStream();
+ try {
+ if(is==null) {
+ is = huc.getInputStream();
+ }
+ if(is!=null) {
+ errContent = new StringBuilder();
+ int c;
+ while((c=is.read())>=0) {
+ errContent.append((char)c);
+ }
+ }
+ } catch (IOException e) {
+ exception = e;
+ }
+ }
+
+ // Typically only used by Read
+ public StringBuilder inputStreamToString(InputStream is) {
+ // Avoids Carriage returns, and is reasonably efficient, given
+ // the buffer reads.
+ try {
+ StringBuilder sb = new StringBuilder();
+ Reader rdr = new InputStreamReader(is);
+ try {
+ char[] buf = new char[256];
+ int read;
+ while ((read = rdr.read(buf)) >= 0) {
+ sb.append(buf, 0, read);
+ }
+ } finally {
+ rdr.close();
+ }
+ return sb;
+ } catch (IOException e) {
+ exception = e;
+ return null;
+ }
+ }
+
+
+ @Override
+ public int code() {
+ return respCode;
+ }
+
+ public HttpURLConnection huc() {
+ return huc;
+ }
+
+ public IOException exception() {
+ return exception;
+ }
+
+ public String respMessage() {
+ return respMessage;
+ }
+
+ @Override
+ public String header(String tag) {
+ return huc.getHeaderField(tag);
+ }
+
+ public void close() {
+ if(huc!=null) {
+ huc.disconnect();
+ }
+ }
+ }
+
+ @Override
+ public <T> Future<T> futureCreate(Class<T> t) {
+ return new HFuture<T>(huc) {
+ public boolean evalInfo(HttpURLConnection huc) {
+ return respCode==201;
+ }
+
+ @Override
+ public String body() {
+ if (errContent != null) {
+ return errContent.toString();
+
+ } else if (respMessage != null) {
+ return respMessage;
+ }
+ return "";
+ }
+ };
+ }
+
+ @Override
+ public Future<String> futureReadString() {
+ return new HFuture<String>(huc) {
+ public boolean evalInfo(HttpURLConnection huc) throws IOException {
+ if (respCode == 200) {
+ StringBuilder sb = inputStreamToString(huc.getInputStream());
+ if (sb != null) {
+ value = sb.toString();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String body() {
+ if (value != null) {
+ return value;
+ } else if (errContent != null) {
+ return errContent.toString();
+ } else if (respMessage != null) {
+ return respMessage;
+ }
+ return "";
+ }
+
+ };
+ }
+
+ @Override
+ public <T> Future<T> futureRead(final RosettaDF<T> df, final TYPE type) {
+ return new HFuture<T>(huc) {
+ private Data<T> data;
+
+ public boolean evalInfo(HttpURLConnection huc) throws APIException, IOException {
+ if (respCode == 200) {
+ data = df.newData().in(type).load(huc.getInputStream());
+ value = data.asObject();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String body() {
+ if (data != null) {
+ try {
+ return data.asString();
+ } catch (APIException e) {
+ }
+ } else if (errContent != null) {
+ return errContent.toString();
+ } else if (respMessage != null) {
+ return respMessage;
+ }
+ return "";
+ }
+ };
+ }
+
+ @Override
+ public <T> Future<T> future(final T t) {
+ return new HFuture<T>(huc) {
+ public boolean evalInfo(HttpURLConnection huc) {
+ if (respCode == 200) {
+ value = t;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String body() {
+ if (errContent != null) {
+ return errContent.toString();
+ } else if (respMessage != null) {
+ return respMessage;
+ }
+ return Integer.toString(respCode);
+ }
+ };
+ }
+
+ @Override
+ public Future<Void> future(final HttpServletResponse resp, final int expected) throws APIException {
+ return new HFuture<Void>(huc) {
+ public boolean evalInfo(HttpURLConnection huc) throws IOException, APIException {
+ resp.setStatus(respCode);
+ int read;
+ InputStream is;
+ OutputStream os = resp.getOutputStream();
+ if(respCode==expected) {
+ is = huc.getInputStream();
+ // reuse Buffers
+ Pooled<byte[]> pbuff = Rcli.buffPool.get();
+ try {
+ while((read=is.read(pbuff.content))>=0) {
+ os.write(pbuff.content,0,read);
+ }
+ } finally {
+ pbuff.done();
+ }
+ return true;
+ } else {
+ is = huc.getErrorStream();
+ if(is==null) {
+ is = huc.getInputStream();
+ }
+ if(is!=null) {
+ errContent = new StringBuilder();
+ Pooled<byte[]> pbuff = Rcli.buffPool.get();
+ try {
+ while((read=is.read(pbuff.content))>=0) {
+ os.write(pbuff.content,0,read);
+ }
+ } finally {
+ pbuff.done();
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String body() {
+ return errContent==null?respMessage:errContent.toString();
+ }
+ };
+ }
+
+ private static class Header {
+ public final String tag;
+ public final String value;
+
+ public Header(String t, String v) {
+ this.tag = t;
+ this.value = v;
+ }
+
+ public String toString() {
+ return tag + '=' + value;
+ }
+ }
+
+ public String toString() {
+ return "HttpURLConnection Client configured to " + uri.toString();
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/http/HMangr.java b/client/src/main/java/com/att/cadi/http/HMangr.java
new file mode 100644
index 0000000..78aff4e
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HMangr.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.net.ssl.SSLHandshakeException;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.CadiException;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.client.Rcli;
+import com.att.cadi.client.Retryable;
+import com.att.inno.env.APIException;
+
+public class HMangr {
+ private String apiVersion;
+ private int readTimeout, connectionTimeout;
+ public final Locator<URI> loc;
+ private Access access;
+
+ public HMangr(Access access, Locator<URI> loc) {
+ readTimeout = 10000;
+ connectionTimeout=3000;
+ this.loc = loc;
+ this.access = access;
+ }
+
+ /**
+ * Reuse the same service. This is helpful for multiple calls that change service side cached data so that
+ * there is not a speed issue.
+ *
+ * If the service goes down, another service will be substituted, if available.
+ *
+ * @param access
+ * @param loc
+ * @param ss
+ * @param item
+ * @param retryable
+ * @return
+ * @throws URISyntaxException
+ * @throws Exception
+ */
+ public<RET> RET same(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws APIException, CadiException, LocatorException {
+ RET ret = null;
+ boolean retry = true;
+ int retries = 0;
+ Rcli<HttpURLConnection> client = retryable.lastClient();
+ try {
+ do {
+ // if no previous state, get the best
+ if(retryable.item()==null) {
+ retryable.item(loc.best());
+ retryable.lastClient = null;
+ }
+ if(client==null) {
+ Item item = retryable.item();
+ URI uri=loc.get(item);
+ if(uri==null) {
+ loc.invalidate(retryable.item());
+ if(loc.hasItems()) {
+ retryable.item(loc.next(retryable.item()));
+ continue;
+ } else {
+ throw new LocatorException("No clients available for " + loc.toString());
+ }
+ }
+ client = new HRcli(this, uri,item,ss)
+ .connectionTimeout(connectionTimeout)
+ .readTimeout(readTimeout)
+ .apiVersion(apiVersion);
+ } else {
+ client.setSecuritySetter(ss);
+ }
+
+ retry = false;
+ try {
+ ret = retryable.code(client);
+ } catch (APIException | CadiException e) {
+ Item item = retryable.item();
+ loc.invalidate(item);
+ retryable.item(loc.next(item));
+ try {
+ Throwable ec = e.getCause();
+ if(ec instanceof java.net.ConnectException) {
+ if(client!=null && ++retries<2) {
+ access.log(Level.WARN,"Connection refused, trying next available service");
+ retry = true;
+ } else {
+ throw new CadiException("Connection refused, no more available connections to try");
+ }
+ } else if(ec instanceof SSLHandshakeException) {
+ retryable.item(null);
+ throw e;
+ } else if(ec instanceof SocketException) {
+ if("java.net.SocketException: Connection reset".equals(ec.getMessage())) {
+ access.log(Level.ERROR, ec.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");
+ }
+ retryable.item(null);
+ throw e;
+ } else {
+ retryable.item(null);
+ throw e;
+ }
+ } finally {
+ client = null;
+ }
+ } catch (ConnectException e) {
+ Item item = retryable.item();
+ loc.invalidate(item);
+ retryable.item(loc.next(item));
+ }
+ } while(retry);
+ } finally {
+ retryable.lastClient = client;
+ }
+ return ret;
+ }
+
+
+ public<RET> RET best(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ if(loc==null) {
+ throw new LocatorException("No Locator Configured");
+ }
+ retryable.item(loc.best());
+ return same(ss,retryable);
+ }
+ public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable) throws LocatorException, CadiException, APIException {
+ return oneOf(ss,retryable,true,null);
+ }
+
+ public<RET> RET all(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify) throws LocatorException, CadiException, APIException {
+ return oneOf(ss,retryable,notify,null);
+ }
+
+ public<RET> RET oneOf(SecuritySetter<HttpURLConnection> ss, Retryable<RET> retryable,boolean notify,String host) throws LocatorException, CadiException, APIException {
+ RET ret = null;
+ // make sure we have all current references:
+ loc.refresh();
+ for(Item li=loc.first();li!=null;li=loc.next(li)) {
+ URI uri=loc.get(li);
+ if(host!=null && !host.equals(uri.getHost())) {
+ break;
+ }
+ try {
+ ret = retryable.code(new HRcli(this,uri,li,ss));
+ access.log(Level.DEBUG,"Success calling",uri,"during call to all services");
+ } catch (APIException | CadiException e) {
+ Throwable t = e.getCause();
+ if(t!=null && t instanceof ConnectException) {
+ loc.invalidate(li);
+ access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");
+ } else if(t instanceof SSLHandshakeException) {
+ access.log(Level.ERROR,t.getMessage());
+ loc.invalidate(li);
+ } else if(t instanceof SocketException) {
+ if("java.net.SocketException: Connection reset".equals(t.getMessage())) {
+ access.log(Level.ERROR, t.getMessage(), " can mean Certificate Expiration or TLS Protocol issues");
+ }
+ retryable.item(null);
+ throw e;
+ } else {
+ throw e;
+ }
+ } catch (ConnectException e) {
+ loc.invalidate(li);
+ access.log(Level.ERROR,"Connection to",uri,"refused during call to all services");
+ }
+ }
+
+ if(ret == null && notify)
+ throw new LocatorException("No available clients to call");
+ return ret;
+ }
+
+
+ public void close() {
+ // TODO Anything here?
+ }
+
+ public HMangr readTimeout(int timeout) {
+ this.readTimeout = timeout;
+ return this;
+ }
+
+ public int readTimeout() {
+ return readTimeout;
+ }
+
+ public void connectionTimeout(int t) {
+ connectionTimeout = t;
+ }
+
+ public int connectionTimout() {
+ return connectionTimeout;
+ }
+
+ public HMangr apiVersion(String version) {
+ apiVersion = version;
+ return this;
+ }
+
+ public String apiVersion() {
+ return apiVersion;
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/http/HRcli.java b/client/src/main/java/com/att/cadi/http/HRcli.java
new file mode 100644
index 0000000..a55b55a
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HRcli.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.cadi.CadiException;
+import com.att.cadi.LocatorException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.Locator.Item;
+import com.att.cadi.client.EClient;
+import com.att.cadi.client.Rcli;
+import com.att.inno.env.APIException;
+import com.att.inno.env.Data.TYPE;
+
+/**
+ * DME2 Rosetta Client
+ *
+ * JAXB defined JSON or XML over DME2 middleware
+ *
+ *
+ * @param <T>
+ */
+public class HRcli extends Rcli<HttpURLConnection> {
+ private HMangr hman;
+ private Item item;
+ private SecuritySetter<HttpURLConnection> ss;
+
+ public HRcli(HMangr hman, Item locItem, SecuritySetter<HttpURLConnection> secSet) throws URISyntaxException, LocatorException {
+ item=locItem;
+ uri=hman.loc.get(locItem);
+ this.hman = hman;
+ ss=secSet;
+ type = TYPE.JSON;
+ apiVersion = hman.apiVersion();
+ }
+
+ public HRcli(HMangr hman, URI uri, Item locItem, SecuritySetter<HttpURLConnection> secSet) {
+ locItem=item;
+ this.uri = uri;
+ this.hman = hman;
+ ss=secSet;
+ type = TYPE.JSON;
+ apiVersion = hman.apiVersion();
+ }
+
+ @Override
+ protected HRcli clone(URI uri, SecuritySetter<HttpURLConnection> ss) {
+ return new HRcli(hman,uri,item,ss);
+ }
+
+
+
+ /**
+ * Note from Thaniga on 11/5. DME2Client is not expected to be reused... need a fresh one
+ * on each transaction, which is expected to cover the Async aspects.
+ *
+ * @return
+ * @throws APIException
+ * @throws DME2Exception
+ */
+ protected EClient<HttpURLConnection> client() throws CadiException {
+ try {
+ if(uri==null) {
+ Item item = hman.loc.best();
+ if(item==null) {
+ throw new CadiException("No service available for " + hman.loc.toString());
+ }
+ uri = hman.loc.get(item);
+ }
+ return new HClient(ss,uri,connectionTimeout);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.client.Rcli#setSecuritySetter(com.att.cadi.SecuritySetter)
+ */
+ @Override
+ public void setSecuritySetter(SecuritySetter<HttpURLConnection> ss) {
+ this.ss = ss;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.client.Rcli#getSecuritySetter()
+ */
+ @Override
+ public SecuritySetter<HttpURLConnection> getSecuritySetter() {
+ return ss;
+ }
+
+ public void invalidate() throws CadiException {
+ try {
+ hman.loc.invalidate(item);
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+
+ public HRcli setManager(HMangr hman) {
+ this.hman = hman;
+ return this;
+ }
+
+ public String toString() {
+ return uri.toString();
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/http/HTransferSS.java b/client/src/main/java/com/att/cadi/http/HTransferSS.java
new file mode 100644
index 0000000..180a341
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HTransferSS.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.security.Principal;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.client.AbsTransferSS;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+
+
+public class HTransferSS extends AbsTransferSS<HttpURLConnection> {
+ public HTransferSS(Principal principal, String app) throws IOException {
+ super(principal, app);
+ }
+
+ public HTransferSS(Principal principal, String app, SecurityInfoC<HttpURLConnection> si) {
+ super(principal, app, si);
+ }
+
+ @Override
+ public void setSecurity(HttpURLConnection huc) throws CadiException {
+ if(value!=null) {
+ if(defSS==null) {
+ throw new CadiException("Need App Credentials to send message");
+ }
+ defSS.setSecurity(huc);
+ huc.addRequestProperty(Config.CADI_USER_CHAIN, value);
+ }
+ if(securityInfo!=null) {
+ securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);
+ }
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+
+}
diff --git a/client/src/main/java/com/att/cadi/http/HX509SS.java b/client/src/main/java/com/att/cadi/http/HX509SS.java
new file mode 100644
index 0000000..3022c0f
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/http/HX509SS.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.http;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.X509KeyManager;
+
+import com.att.cadi.CadiException;
+import com.att.cadi.SecuritySetter;
+import com.att.cadi.Symm;
+import com.att.cadi.config.Config;
+import com.att.cadi.config.SecurityInfoC;
+import com.att.inno.env.APIException;
+import com.att.inno.env.util.Chrono;
+
+
+public class HX509SS implements SecuritySetter<HttpURLConnection> {
+ private static final byte[] X509 = "x509 ".getBytes();
+ private PrivateKey priv;
+ private byte[] pub;
+ private String cert;
+ private SecurityInfoC<HttpURLConnection> securityInfo;
+ private String algo;
+ private String alias;
+ private static int count = new SecureRandom().nextInt();
+
+ public HX509SS(SecurityInfoC<HttpURLConnection> si) throws APIException, IOException, CertificateEncodingException {
+ this(null,si,false);
+ }
+
+ public HX509SS(SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws APIException, IOException, CertificateEncodingException {
+ this(null,si,asDefault);
+ }
+
+ public HX509SS(final String sendAlias, SecurityInfoC<HttpURLConnection> si) throws APIException, IOException, CertificateEncodingException {
+ this(sendAlias, si, false);
+ }
+
+ public HX509SS(final String sendAlias, SecurityInfoC<HttpURLConnection> si, boolean asDefault) throws APIException, IOException, CertificateEncodingException {
+ securityInfo = si;
+ if((alias=sendAlias) == null) {
+ if(si.default_alias == null) {
+ throw new APIException("JKS Alias is required to use X509SS Security. Use " + Config.CADI_ALIAS +" to set default alias");
+ } else {
+ alias = si.default_alias;
+ }
+ }
+
+ priv=null;
+ X509KeyManager[] xkms = si.getKeyManagers();
+ if(xkms==null || xkms.length==0) {
+ throw new APIException("There are no valid keys available in given Keystores. Wrong Keypass? Expired?");
+ }
+ for(int i=0;priv==null&&i<xkms.length;++i) {
+ priv = xkms[i].getPrivateKey(alias);
+ }
+ for(int i=0;cert==null&&i<xkms.length;++i) {
+ X509Certificate[] chain = xkms[i].getCertificateChain(alias);
+ if(chain!=null&&chain.length>0) {
+ algo = chain[0].getSigAlgName();
+ pub = chain[0].getEncoded();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(pub.length*2);
+ ByteArrayInputStream bais = new ByteArrayInputStream(pub);
+ Symm.base64noSplit.encode(bais,baos,X509);
+ cert = baos.toString();
+
+ /*
+ // Inner Test code, uncomment if fix needed
+ bais = new ByteArrayInputStream(baos.toByteArray());
+ baos = new ByteArrayOutputStream(input.length*2);
+ Symm.base64noSplit().decode(bais,baos,5);
+ byte[] output = baos.toByteArray();
+ String reconstitute = output.toString();
+ System.out.println("ok");
+ CertificateFactory certFactory;
+ try {
+ bais = new ByteArrayInputStream(output);
+ certFactory = CertificateFactory.getInstance("X.509");
+ X509Certificate x509 = (X509Certificate)certFactory.generateCertificate(bais);
+ System.out.println(x509.toString());
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ }
+ */
+ }
+ }
+ if(algo==null) {
+ throw new APIException("X509 Security Setter not configured");
+ }
+ }
+
+ @Override
+ public void setSecurity(HttpURLConnection huc) throws CadiException {
+ if(huc instanceof HttpsURLConnection) {
+ securityInfo.setSocketFactoryOn((HttpsURLConnection)huc);
+ }
+ if(alias==null) { // must be a one-way
+ huc.setRequestProperty("Authorization", cert);
+
+ // Test Signed content
+ try {
+ String data = "SignedContent["+ inc() + ']' + Chrono.dateTime();
+ huc.setRequestProperty("Data", data);
+
+ Signature sig = Signature.getInstance(algo);
+ sig.initSign(priv);
+ sig.update(data.getBytes());
+ byte[] signature = sig.sign();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream((int)(signature.length*1.3));
+ ByteArrayInputStream bais = new ByteArrayInputStream(signature);
+ Symm.base64noSplit.encode(bais, baos);
+ huc.setRequestProperty("Signature", new String(baos.toByteArray()));
+
+ } catch (Exception e) {
+ throw new CadiException(e);
+ }
+ }
+ }
+
+ private synchronized int inc() {
+ return ++count;
+ }
+
+ /* (non-Javadoc)
+ * @see com.att.cadi.SecuritySetter#getID()
+ */
+ @Override
+ public String getID() {
+ return alias;
+ }
+
+ @Override
+ public int setLastResponse(int respCode) {
+ return 0;
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/locator/DME2Locator.java b/client/src/main/java/com/att/cadi/locator/DME2Locator.java
new file mode 100644
index 0000000..72a5f73
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/DME2Locator.java
@@ -0,0 +1,346 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Properties;
+import java.util.Random;
+import java.security.SecureRandom;
+
+//import com.att.aft.dme2.api.DME2Endpoint;
+import com.att.aft.dme2.api.DME2Exception;
+import com.att.aft.dme2.api.DME2Manager;
+import com.att.aft.dme2.api.DME2Server;
+import com.att.aft.dme2.manager.registry.DME2Endpoint;
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.PropAccess;
+
+public class DME2Locator implements Locator<URI> {
+ private DME2Manager dm;
+ private DME2Endpoint[] endpoints;
+ private Access access;
+ private String service;
+ private String version;
+ private String routeOffer;
+ private String envContext;
+ private String thisMachine;
+ private String pathInfo;
+ private int thisPort;
+ private boolean removeSelf;
+ private final static SecureRandom random = new SecureRandom();
+
+ // Default is to not bother trying to remove self
+ public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer) throws DME2Exception, UnknownHostException, LocatorException {
+ this(access,dm,service,version,envContext,routeOffer,false);
+ }
+
+ public DME2Locator(Access access, DME2Manager dm, String service, String version, String envContext, String routeOffer, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {
+ this.access = access;
+ if(dm==null) {
+ this.dm = new DME2Manager("DME2Locator created DME2Manager",System.getProperties());
+ } else {
+ this.dm = dm;
+ }
+ this.service = service;
+ this.version = version;
+ this.envContext = envContext;
+ this.routeOffer = routeOffer;
+ refresh();
+ if(thisMachine==null) {
+ // Can't get from dm...
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ thisPort = dm.getPort();
+ }
+
+ this.removeSelf = removeSelf;
+ }
+
+ // Default is to not bother trying to remove self
+ public DME2Locator(Access access, DME2Manager dm, String aafurl) throws DME2Exception, UnknownHostException, LocatorException {
+ this(access,dm,aafurl,false);
+ }
+
+ public DME2Locator(Access access, DME2Manager dm, String aafurl, boolean removeSelf) throws DME2Exception, UnknownHostException, LocatorException {
+ if(aafurl==null) {
+ throw new LocatorException("URL is null");
+ }
+ this.access = access;
+ if(dm==null) {
+ Properties dprops;
+ if(access instanceof PropAccess) {
+ dprops = ((PropAccess)access).getDME2Properties();
+ } else {
+ dprops = System.getProperties();
+ }
+ dm = this.dm = new DME2Manager("DME2Locator created DME2Manager",dprops);
+ } else {
+ this.dm = dm;
+ }
+ String[] split = aafurl.split("/");
+ StringBuilder sb = new StringBuilder();
+ boolean dme2Entered = false;
+ for(String s : split) {
+ if(s.startsWith("service=")) {
+ this.service = s.substring(8);
+ } else if(s.startsWith("version=")) {
+ this.version = s.substring(8);
+ } else if(s.startsWith("envContext=")) {
+ this.envContext = s.substring(11);
+ } else if(s.startsWith("routeOffer=")) {
+ this.routeOffer = s.substring(11);
+ dme2Entered = true;
+ } else if(dme2Entered) {
+ sb.append('/');
+ sb.append(s);
+ }
+ }
+ pathInfo = sb.toString();
+ thisMachine = dm.getHostname();
+ if(thisMachine==null) {
+ // Can't get from dm...
+ thisMachine = InetAddress.getLocalHost().getHostName();
+ thisPort = 0;
+ } else {
+ thisPort = dm.getPort();
+ }
+ this.removeSelf=removeSelf;
+ refresh();
+ }
+
+ @Override
+ public boolean refresh() {
+ try {
+ dm.refresh();
+ //endpoints = dm.findEndpoints(service, version, envContext, routeOffer, true);
+ if(removeSelf) {
+// for(int i=0;i<endpoints.length;++i) {
+// if(endpoints[i].getPort()==thisPort && endpoints[i].getHost().equals(thisMachine))
+// endpoints[i]=null;
+ }
+ //}
+ //return endpoints.length!=0;
+ } catch (Exception e) {
+ access.log(Level.ERROR, e.getMessage());
+ }
+ return false;
+ }
+
+ private String noEndpointsString() {
+ StringBuilder sb = new StringBuilder("No DME2 Endpoints found for ");
+ sb.append(service);
+ sb.append('/');
+ sb.append(version);
+ sb.append('/');
+ sb.append(envContext);
+ sb.append('/');
+ sb.append(routeOffer);
+ return sb.toString();
+ }
+
+ @Override
+ public URI get(Locator.Item item) throws LocatorException {
+ if(!hasItems())
+ throw new LocatorException(noEndpointsString());
+ if(item == null)
+ return null;
+
+ DME2Item li = ((DME2Item)item);
+ // if URI has been created, use it
+ if(li.uri!=null)return li.uri;
+
+ // URI not created, create it
+// if(li.idx<endpoints.length) {
+// DME2Endpoint de = endpoints[li.idx];
+// if(de!=null) {
+// try {
+// return li.uri=new URI(de.getProtocol().toLowerCase(),null,de.getHost(),de.getPort(),pathInfo,null,null);
+// } catch (URISyntaxException e) {
+// throw new LocatorException(e);
+// }
+// }
+// }
+ return null;
+ }
+
+ @Override
+ public boolean hasItems() {
+ //return endpoints!=null && endpoints.length>0;
+ return true;
+ }
+
+ @Override
+ public void invalidate(Locator.Item item) throws LocatorException {
+ if(item instanceof DME2Item) {
+ int idx = ((DME2Item)item).idx;
+// if(idx<endpoints.length) {
+// DME2Endpoint uhoh = endpoints[idx]; // Sometimes, DME2Endpoint, at least on File system, returns bogus entries.
+// endpoints[idx]=null;
+// boolean noneLeft=true;
+// for(int i=0;i<endpoints.length && noneLeft;++i) {
+// noneLeft = endpoints[i]==null;
+// }
+// if(noneLeft && refresh()) { // make sure DME2 isn't giving us the same invalidated entry...
+// for(int i=0;i<endpoints.length && noneLeft;++i) {
+// DME2Endpoint ep = endpoints[i];
+// if(ep != null &&
+// ep.getHost().equals(uhoh.getHost()) &&
+// ep.getPort()==uhoh.getPort()) {
+// endpoints[i]=null;
+// }
+// }
+// }
+//
+// }
+ }
+ }
+
+ public class DME2Item implements Locator.Item {
+ private final int idx;
+ private URI uri;
+ private DME2Item(int i) {
+ idx = i;
+ uri = null;
+ }
+ }
+
+ @Override
+ public DME2Item best() throws LocatorException {
+ if(!hasItems()) // checks endpoints
+ if(!refresh()) throw new LocatorException("No DME2 Endpoints Available");
+
+ // Some endpoints in Array are null. Need sub array of usable endpoints
+ //int usable[] = new int[endpoints.length];
+ int count=0;
+int[] usable = null;
+ // for(int i=0;i<endpoints.length;++i) {
+// if(endpoints[i]!=null) {
+// usable[count++] = i;
+// }
+// }
+ switch(count) {
+ case 0: refresh(); return null;
+ case 1: return new DME2Item(usable[0]);
+ default:
+ int samemach[] = new int[count];
+ int samecount = 0,closecount=0;
+ // has to be sortable
+ Integer closemach[] = new Integer[count];
+
+ // Analyze for Same Machine or Remote machines
+// for(int i=0;i<count;++i) {
+// DME2Endpoint ep = endpoints[usable[i]];
+// String host = ep.getHost();
+// if(thisMachine.equalsIgnoreCase(host)) {
+// samemach[samecount++] = usable[i];
+// } else {
+// closemach[closecount++] = usable[i];
+// }
+// }
+
+ switch(samecount) {
+ case 0: break;
+ case 1: return new DME2Item(samemach[0]);
+ default: // return randomized is multiple Endpoints on local machine.
+ int i = random.nextInt();
+ return new DME2Item(usable[Math.abs(i%samecount)]);
+ }
+
+ // Analyze for closest remote
+ switch(closecount) {
+ case 0: return null;
+ case 1: return new DME2Item(closemach[0]);
+ default: // return closest machine
+ DoubIndex remote[] = new DoubIndex[closecount];
+ int remotecount = 0;
+ for(int i=0;i<closecount;++i) {
+ //DME2Endpoint de = endpoints[usable[i]];
+ // remote[remotecount++] = new DoubIndex(de.getDistance(),i);
+ }
+ Arrays.sort(remote,new Comparator<DoubIndex> () {
+ @Override
+ public int compare(DoubIndex a, DoubIndex b) {
+ if(a.d<b.d) return -1;
+ if(a.d>b.d) return 1;
+ return (random.nextInt()%1)==0?1:0;// randomize if the same
+ }
+
+ });
+ return new DME2Item(remote[0].idx);
+ }
+ }
+ }
+
+ private static class DoubIndex {
+ public final double d;
+ public final int idx;
+
+ public DoubIndex(double doub, int i) {
+ d = doub;
+ idx = i;
+ }
+ }
+ @Override
+ public DME2Item first() {
+// if(endpoints==null)return null;
+// for(int i=0;i<endpoints.length;++i) {
+// if(endpoints[i]!=null)
+// return new DME2Item(i);
+// }
+ return null;
+ }
+
+ @Override
+ public DME2Item next(Locator.Item item) throws LocatorException {
+ //if(endpoints==null || endpoints.length==0 || !(item instanceof DME2Item))return null;
+ int idx = ((DME2Item)item).idx +1;
+// for(int i=idx;i<endpoints.length;++i) {
+// if(endpoints[i]!=null)
+// return new DME2Item(i);
+// }
+// This is a mistake.. will start infinite loops
+// // Did not have any at end... try beginning
+// for(int i=0;i<idx-1;++i) {
+// if(endpoints[i]!=null)
+// return new Item(i);
+// }
+// // If still nothing, refresh
+// refresh();
+ return null;
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/locator/DNSLocator.java b/client/src/main/java/com/att/cadi/locator/DNSLocator.java
new file mode 100644
index 0000000..9fbf2d4
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/DNSLocator.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.att.cadi.Access;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.Access.Level;
+
+public class DNSLocator implements Locator<URI> {
+ private static enum Status {UNTRIED, OK, INVALID, SLOW};
+ private static final int CHECK_TIME = 3000;
+
+ private String host, protocol;
+ private Access access;
+ private Host[] hosts;
+ private int startPort, endPort;
+ private String suffix;
+
+ public DNSLocator(Access access, String protocol, String host, String range) {
+ this.host = host;
+ this.protocol = protocol;
+ this.access = access;
+ int dash = range.indexOf('-');
+ if(dash<0) {
+ startPort = endPort = Integer.parseInt(range);
+ } else {
+ startPort = Integer.parseInt(range.substring(0,dash));
+ endPort = Integer.parseInt(range.substring(dash + 1));
+ }
+ refresh();
+ }
+
+ @Override
+ public URI get(Item item) throws LocatorException {
+ return hosts[((DLItem)item).cnt].uri;
+ }
+
+ @Override
+ public boolean hasItems() {
+ for(Host h : hosts) {
+ if(h.status==Status.OK) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void invalidate(Item item) {
+ DLItem di = (DLItem)item;
+ hosts[di.cnt].status = Status.INVALID;
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ // not a good "best"
+ for(int i=0;i<hosts.length;++i) {
+ switch(hosts[i].status) {
+ case OK:
+ return new DLItem(i);
+ case INVALID:
+ break;
+ case SLOW:
+ break;
+ case UNTRIED:
+ try {
+ if(hosts[i].ia.isReachable(CHECK_TIME)) {
+ hosts[i].status = Status.OK;
+ return new DLItem(i);
+ }
+ } catch (IOException e) {
+ throw new LocatorException(e);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ throw new LocatorException("No Available URIs for " + host);
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return new DLItem(0);
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ DLItem di = (DLItem)item;
+ if(++di.cnt<hosts.length) {
+ return di;
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean refresh() {
+ try {
+ InetAddress[] ias = InetAddress.getAllByName(host);
+ Host[] temp = new Host[ias.length * (1 + endPort - startPort)];
+ int cnt = -1;
+ for(int j=startPort; j<=endPort; ++j) {
+ for(int i=0;i<ias.length;++i) {
+ temp[++cnt] = new Host(ias[i], j, suffix);
+ }
+ }
+ hosts = temp;
+ return true;
+ } catch (Exception e) {
+ access.log(Level.ERROR, e);
+ }
+ return false;
+ }
+
+ private class Host {
+ private URI uri;
+ private InetAddress ia;
+ private Status status;
+
+ public Host(InetAddress inetAddress, int port, String suffix) throws URISyntaxException {
+ ia = inetAddress;
+ uri = new URI(protocol,null,inetAddress.getHostAddress(),port,suffix,null,null);
+ status = Status.UNTRIED;
+ }
+ }
+
+ private class DLItem implements Item {
+ public DLItem(int i) {
+ cnt = i;
+ }
+
+ private int cnt;
+ }
+
+ public void destroy() {}
+}
diff --git a/client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java b/client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java
new file mode 100644
index 0000000..ecbdfaa
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/HClientHotPeerLocator.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import com.att.cadi.Access;
+import com.att.cadi.LocatorException;
+import com.att.cadi.http.HClient;
+import com.att.cadi.http.HX509SS;
+
+public class HClientHotPeerLocator extends HotPeerLocator<HClient> {
+ private final HX509SS ss;
+
+ public HClientHotPeerLocator(Access access, String urlstr, long invalidateTime, String localLatitude,
+ String localLongitude, HX509SS ss) throws LocatorException {
+ super(access, urlstr, invalidateTime, localLatitude, localLongitude);
+
+ this.ss = ss;
+ }
+
+ @Override
+ protected HClient _newClient(String clientInfo) throws LocatorException {
+ try {
+ int idx = clientInfo.indexOf('/');
+ return new HClient(ss,new URI("https://"+(idx<0?clientInfo:clientInfo.substring(0, idx))),3000);
+ } catch (URISyntaxException e) {
+ throw new LocatorException(e);
+ }
+ }
+
+ @Override
+ protected HClient _invalidate(HClient client) {
+ return null;
+ }
+
+ @Override
+ protected void _destroy(HClient client) {
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/locator/HotPeerLocator.java b/client/src/main/java/com/att/cadi/locator/HotPeerLocator.java
new file mode 100644
index 0000000..f8a1546
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/HotPeerLocator.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+import com.att.cadi.Access;
+import com.att.cadi.Access.Level;
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.cadi.routing.GreatCircle;
+import com.att.inno.env.util.Split;
+
+/**
+ * This Locator is to handle Hot Peer load protection, when the Servers are
+ * 1) Static
+ * 2) Well known client URL
+ *
+ * The intention is to change traffic over to the Hot Peer, if a server goes down, and reinstate
+ * when it is back up.
+ *
+ * Example of this kind of Service is a MS Certificate Server
+ *
+ *
+ *
+ * @param <CLIENT>
+ */
+public abstract class HotPeerLocator<CLIENT> implements Locator<CLIENT> {
+ private final String[] urlstrs;
+ private final CLIENT[] clients;
+ private final long[] failures;
+ private final double[] distances;
+ private int preferred;
+ private long invalidateTime;
+ private Thread refreshThread;
+ protected Access access;
+
+ /**
+ * Construct: Expect one or more Strings in the form:
+ * 192.555.112.223:39/38.88087/-77.30122
+ * separated by commas
+ *
+ * @param trans
+ * @param urlstr
+ * @param invalidateTime
+ * @param localLatitude
+ * @param localLongitude
+ * @throws LocatorException
+ */
+ @SuppressWarnings("unchecked")
+ protected HotPeerLocator(Access access, final String urlstr, final long invalidateTime, final String localLatitude, final String localLongitude) throws LocatorException {
+ this.access = access;
+ urlstrs = Split.split(',', urlstr);
+ clients = (CLIENT[])new Object[urlstrs.length];
+ failures = new long[urlstrs.length];
+ distances= new double[urlstrs.length];
+ this.invalidateTime = invalidateTime;
+
+ double distance = Double.MAX_VALUE;
+ for(int i=0;i<urlstrs.length;++i) {
+ String[] info = Split.split('/', urlstrs[i]);
+ if(info.length<3) {
+ throw new LocatorException("Configuration needs LAT and LONG, i.e. ip:port/lat/long");
+ }
+ try {
+ clients[i] = _newClient(urlstrs[i]);
+ failures[i] = 0L;
+ } catch(LocatorException le) {
+ failures[i] = System.currentTimeMillis()+invalidateTime;
+ }
+
+ double d = GreatCircle.calc(info[1],info[2],localLatitude,localLongitude);
+ distances[i]=d;
+
+ // find preferred server
+ if(d<distance) {
+ preferred = i;
+ distance=d;
+ }
+ }
+
+ access.printf(Level.INIT,"Preferred Client is %s",urlstrs[preferred]);
+ for(int i=0;i<urlstrs.length;++i) {
+ if(i!=preferred) {
+ access.printf(Level.INIT,"Alternate Client is %s",urlstrs[i]);
+ }
+ }
+ }
+
+ protected abstract CLIENT _newClient(String hostInfo) throws LocatorException;
+ /**
+ * If client can reconnect, then return. Otherwise, destroy and return null;
+ * @param client
+ * @return
+ * @throws LocatorException
+ */
+ protected abstract CLIENT _invalidate(CLIENT client);
+
+ protected abstract void _destroy(CLIENT client);
+
+ @Override
+ public Item best() throws LocatorException {
+ if(failures[preferred]==0L) {
+ return new HPItem(preferred);
+ } else {
+ long now = System.currentTimeMillis();
+ double d = Double.MAX_VALUE;
+ int best = -1;
+ boolean tickle = false;
+ // try for best existing client
+ for(int i=0;i<urlstrs.length;++i) {
+ if(failures[i]<now && distances[i]<d) {
+ if(clients[i]!=null) {
+ best = i;
+ break;
+ } else {
+ tickle = true; // There's some failed clients which can be restored
+ }
+ }
+ }
+ if(best<0 && tickle) {
+ tickle=false;
+ if(refresh()) {
+ // try again
+ for(int i=0;i<urlstrs.length;++i) {
+ if(failures[i]==0L && distances[i]<d) {
+ if(clients[i]!=null) {
+ best = i;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * If a valid client is available, but there are some that can refresh, return the client immediately
+ * but start a Thread to do the background Client setup.
+ */
+ if(tickle) {
+ synchronized(clients) {
+ if(refreshThread==null) {
+ refreshThread = new Thread(new Runnable(){
+ @Override
+ public void run() {
+ refresh();
+ refreshThread = null;
+ }
+ });
+ refreshThread.setDaemon(true);
+ refreshThread.start();
+ }
+ }
+ }
+
+ if(best<0) {
+ throw new LocatorException("No Clients available");
+ }
+
+
+ return new HPItem(best);
+ }
+ }
+
+
+ @Override
+ public CLIENT get(Item item) throws LocatorException {
+ HPItem hpi = (HPItem)item;
+ CLIENT c = clients[hpi.idx];
+ if(c==null) {
+ if(failures[hpi.idx]>System.currentTimeMillis()) {
+ throw new LocatorException("Client requested is invalid");
+ } else {
+ synchronized(clients) {
+ c = _newClient(urlstrs[hpi.idx]);
+ failures[hpi.idx]=0L;
+ }
+ }
+ } else if(failures[hpi.idx]>0){
+ throw new LocatorException("Client requested is invalid");
+ }
+ return c;
+ }
+
+ public String info(Item item) {
+ HPItem hpi = (HPItem)item;
+ if(hpi!=null && hpi.idx<urlstrs.length) {
+ return urlstrs[hpi.idx];
+ } else {
+ return "Invalid Item";
+ }
+ }
+
+ @Override
+ public boolean hasItems() {
+ for(int i=0;i<clients.length;++i) {
+ if(clients[i]!=null && failures[i]==0L) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public synchronized void invalidate(Item item) throws LocatorException {
+ HPItem hpi = (HPItem)item;
+ failures[hpi.idx] = System.currentTimeMillis() + invalidateTime;
+ CLIENT c = clients[hpi.idx];
+ clients[hpi.idx] = _invalidate(c);
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return new HPItem(0);
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ HPItem hpi = (HPItem)item;
+ if(++hpi.idx>=clients.length) {
+ return null;
+ }
+ return hpi;
+ }
+
+ @Override
+ public boolean refresh() {
+ boolean force = !hasItems(); // If no Items at all, reset
+ boolean rv = true;
+ long now = System.currentTimeMillis();
+ for(int i=0;i<clients.length;++i) {
+ if(failures[i]>0L && (failures[i]<now || force)) { // retry
+ try {
+ synchronized(clients) {
+ if(clients[i]==null) {
+ clients[i]=_newClient(urlstrs[i]);
+ }
+ failures[i]=0L;
+ }
+ } catch (LocatorException e) {
+ failures[i]=now+invalidateTime;
+ rv = false;
+ }
+ }
+ }
+ return rv;
+ }
+
+ @Override
+ public void destroy() {
+ for(int i=0;i<clients.length;++i) {
+ if(clients[i]!=null) {
+ _destroy(clients[i]);
+ clients[i] = null;
+ }
+ }
+ }
+
+ private static class HPItem implements Item {
+ private int idx;
+
+ public HPItem(int i) {
+ idx = i;
+ }
+ }
+
+
+ /*
+ * Convenience Functions
+ */
+ public CLIENT bestClient() throws LocatorException {
+ return get(best());
+ }
+
+ public boolean invalidate(CLIENT client) throws LocatorException {
+ for(int i=0;i<clients.length;++i) {
+ if(clients[i]==client) { // yes, "==" is appropriate here.. Comparing Java Object Reference
+ invalidate(new HPItem(i));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ }
diff --git a/client/src/main/java/com/att/cadi/locator/PropertyLocator.java b/client/src/main/java/com/att/cadi/locator/PropertyLocator.java
new file mode 100644
index 0000000..011e42c
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/locator/PropertyLocator.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.locator;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.security.SecureRandom;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.att.cadi.Locator;
+import com.att.cadi.LocatorException;
+import com.att.inno.env.util.Split;
+
+public class PropertyLocator implements Locator<URI> {
+ private final URI [] orig;
+ private PLItem[] current;
+ private int end;
+ private final SecureRandom random;
+ private URI[] resolved;
+ private long lastRefreshed=0L;
+ private long minRefresh;
+ private long backgroundRefresh;
+
+ public PropertyLocator(String locList) throws LocatorException {
+ this(locList,10000L, 1000*60*20); // defaults, do not refresh more than once in 10 seconds, Refresh Locator every 20 mins.
+ }
+ /**
+ * comma delimited root url list
+ *
+ * @param locList
+ * @throws LocatorException
+ */
+ public PropertyLocator(String locList, long minRefreshMillis, long backgroundRefreshMillis) throws LocatorException {
+ minRefresh = minRefreshMillis;
+ backgroundRefresh = backgroundRefreshMillis;
+ if(locList==null) {
+ throw new LocatorException("No Location List given for PropertyLocator");
+ }
+ String[] locarray = Split.split(',',locList);
+ List<URI> uriList = new ArrayList<URI>();
+
+ random = new SecureRandom();
+
+ for(int i=0;i<locarray.length;++i) {
+ try {
+ int range = locarray[i].indexOf(":[");
+ if(range<0) {
+ uriList.add(new URI(locarray[i]));
+ } else {
+ int dash = locarray[i].indexOf('-',range+2);
+ int brac = locarray[i].indexOf(']',dash+1);
+ int start = Integer.parseInt(locarray[i].substring(range+2, dash));
+ int end = Integer.parseInt(locarray[i].substring(dash+1, brac));
+ for(int port=start;port<=end;++port) {
+ uriList.add(new URI(locarray[i].substring(0, range+1)+port));
+ }
+ }
+ } catch (NumberFormatException nf) {
+ throw new LocatorException("Invalid URI format: " + locarray[i]);
+ } catch (URISyntaxException e) {
+ throw new LocatorException(e);
+ }
+ }
+ orig = new URI[uriList.size()];
+ uriList.toArray(orig);
+
+ refresh();
+ new Timer("PropertyLocator Refresh Timer",true).scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ refresh();
+ }
+ }, backgroundRefresh,backgroundRefresh);
+
+ }
+
+ @Override
+ public URI get(Item item) throws LocatorException {
+ synchronized(orig) {
+ if(item==null) {
+ return null;
+ } else {
+ return resolved[((PLItem)item).idx];
+ }
+ }
+ }
+
+ @Override
+ public Item first() throws LocatorException {
+ return end>0?current[0]:null;
+ }
+
+ @Override
+ public boolean hasItems() {
+ return end>0;
+ }
+
+ @Override
+ public Item next(Item item) throws LocatorException {
+ if(item==null) {
+ return null;
+ } else {
+ int spot;
+ if((spot=(((PLItem)item).order+1))>=end)return null;
+ return current[spot];
+ }
+ }
+
+ @Override
+ public synchronized void invalidate(Item item) throws LocatorException {
+ if(--end<=0) {
+ refresh();
+ return;
+ }
+ PLItem pli = (PLItem)item;
+ int i,order;
+ for(i=0;i<end;++i) {
+ if(pli==current[i])break;
+ }
+ order = current[i].order;
+ for(;i<end;++i) {
+ current[i]=current[i+1];
+ current[i].order=order++;
+ }
+ current[end]=pli;
+ }
+
+ @Override
+ public Item best() throws LocatorException {
+ if(current.length==0) {
+ refresh();
+ }
+ switch(current.length) {
+ case 0:
+ return null;
+ case 1:
+ return current[0];
+ default:
+ return current[Math.abs(random.nextInt())%current.length];
+ }
+ }
+
+ @Override
+ public synchronized boolean refresh() {
+ if(System.currentTimeMillis()>lastRefreshed) {
+ // Build up list
+ List<URI> resolve = new ArrayList<URI>();
+ String realname;
+ for(int i = 0; i < orig.length ; ++i) {
+ try {
+ InetAddress ia[] = InetAddress.getAllByName(orig[i].getHost());
+
+ URI o,n;
+ for(int j=0;j<ia.length;++j) {
+ o = orig[i];
+ Socket socket = new Socket();
+ try {
+ realname=ia[j].getCanonicalHostName();
+ socket.connect(new InetSocketAddress(realname,o.getPort()),3000);
+ if(socket.isConnected()) {
+ n = new URI(
+ o.getScheme(),
+ o.getUserInfo(),
+ realname,
+ o.getPort(),
+ o.getPath(),
+ o.getQuery(),
+ o.getFragment()
+ );
+ resolve.add(n);
+ }
+ } catch (IOException e) {
+ } finally {
+ if(!socket.isClosed()) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ // nothing to do.
+ }
+ }
+ }
+ }
+ } catch (UnknownHostException | URISyntaxException e) {
+ // Note: Orig Name already known as valid, based on constructor
+ }
+ }
+ end=resolve.size();
+ PLItem[] newCurrent;
+ if(current==null || current.length!=end) {
+ newCurrent = new PLItem[end];
+ } else {
+ newCurrent = current;
+ }
+
+ for(int i=0; i< end; ++i) {
+ if(newCurrent[i]==null){
+ newCurrent[i]=new PLItem(i);
+ } else {
+ newCurrent[i].idx=newCurrent[i].order=i;
+ }
+ }
+ synchronized(orig) {
+ resolved = new URI[end];
+ resolve.toArray(resolved);
+ current = newCurrent;
+ }
+ lastRefreshed = System.currentTimeMillis()+minRefresh;
+ return !resolve.isEmpty();
+ } else {
+ return false;
+ }
+ }
+
+ private class PLItem implements Item {
+ public int idx,order;
+
+ public PLItem(int i) {
+ idx = order =i;
+ }
+
+ public String toString() {
+ return "Item: " + idx + " order: " + order;
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for(URI uri : orig) {
+ boolean isResolved=false;
+ if(uri!=null) {
+ if(first) {
+ first = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(uri.toString());
+ sb.append(" [");
+ for(URI u2 : resolved) {
+ if(uri.equals(u2)) {
+ isResolved = true;
+ break;
+ }
+ }
+ sb.append(isResolved?"X]\n":" ]");
+ }
+ }
+ return sb.toString();
+ }
+
+ public void destroy() {
+ }
+}
diff --git a/client/src/main/java/com/att/cadi/routing/GreatCircle.java b/client/src/main/java/com/att/cadi/routing/GreatCircle.java
new file mode 100644
index 0000000..5a58920
--- /dev/null
+++ b/client/src/main/java/com/att/cadi/routing/GreatCircle.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * ============LICENSE_START====================================================
+ * * org.onap.aai
+ * * ===========================================================================
+ * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * * Copyright © 2017 Amdocs
+ * * ===========================================================================
+ * * 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====================================================
+ * *
+ * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ * *
+ ******************************************************************************/
+package com.att.cadi.routing;
+
+import com.att.inno.env.util.Split;
+
+public class GreatCircle {
+ // Note: multiplying by this constant is faster than calling Math equivalent function
+ private static final double DEGREES_2_RADIANS = Math.PI/180.0;
+
+ public static final double DEGREES_2_NM = 60;
+ public static final double DEGREES_2_KM = DEGREES_2_NM * 1.852; // 1.852 is exact ratio per 1929 Standard Treaty, adopted US 1954
+ public static final double DEGREES_2_MI = DEGREES_2_NM * 1.1507795;
+
+ /**
+ *
+ * Calculate the length of an arc on a perfect sphere based on Latitude and Longitudes of two points
+ * Parameters are in Degrees (i.e. the coordinate system you get from GPS, Mapping WebSites, Phones, etc)
+ *
+ * L1 = Latitude of point A
+ * G1 = Longitude of point A
+ * L2 = Latitude of point B
+ * G2 = Longitude of point B
+ *
+ * d = acos (sin(L1)*sin(L2) + cos(L1)*cos(L2)*cos(G1 - G2))
+ *
+ * Returns answer in Degrees
+ *
+ * Since there are 60 degrees per nautical miles, you can convert to NM by multiplying by 60
+ *
+ * Essential formula from a Princeton website, the "Law of Cosines" method.
+ *
+ * Refactored cleaned up for speed 3/8/2013
+ *
+ * @param latA
+ * @param lonA
+ * @param latB
+ * @param lonB
+ * @return
+ */
+ public static double calc(double latA, double lonA, double latB, double lonB) {
+ // Formula requires Radians. Expect Params to be Coordinates (Degrees)
+ // Simple ratio, quicker than calling Math.toRadians()
+ latA *= DEGREES_2_RADIANS;
+ lonA *= DEGREES_2_RADIANS;
+ latB *= DEGREES_2_RADIANS;
+ lonB *= DEGREES_2_RADIANS;
+
+ return Math.acos(
+ Math.sin(latA) * Math.sin(latB) +
+ Math.cos(latA) * Math.cos(latB) * Math.cos(lonA-lonB)
+ )
+ / DEGREES_2_RADIANS;
+ }
+
+ /**
+ * Convert from "Lat,Long Lat,Long" String format
+ * "Lat,Long,Lat,Long" Format
+ * or all four entries "Lat Long Lat Long"
+ *
+ * (Convenience function)
+ *
+ * Since Distance is positive, a "-1" indicates an error in String formatting
+ */
+ public static double calc(String ... coords) {
+ try {
+ String [] array;
+ switch(coords.length) {
+ case 1:
+ array = Split.split(',',coords[0]);
+ if(array.length!=4)return -1;
+ return calc(
+ Double.parseDouble(array[0]),
+ Double.parseDouble(array[1]),
+ Double.parseDouble(array[2]),
+ Double.parseDouble(array[3])
+ );
+ case 2:
+ array = Split.split(',',coords[0]);
+ String [] array2 = Split.split(',',coords[1]);
+ if(array.length!=2 || array2.length!=2)return -1;
+ return calc(
+ Double.parseDouble(array[0]),
+ Double.parseDouble(array[1]),
+ Double.parseDouble(array2[0]),
+ Double.parseDouble(array2[1])
+ );
+ case 4:
+ return calc(
+ Double.parseDouble(coords[0]),
+ Double.parseDouble(coords[1]),
+ Double.parseDouble(coords[2]),
+ Double.parseDouble(coords[3])
+ );
+
+ default:
+ return -1;
+ }
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+
+}
+
+///**
+//* Haverside method, from Princeton
+//*
+//* @param alat
+//* @param alon
+//* @param blat
+//* @param blon
+//* @return
+//*/
+//public static double calc3(double alat, double alon, double blat, double blon) {
+// alat *= DEGREES_2_RADIANS;
+// alon *= DEGREES_2_RADIANS;
+// blat *= DEGREES_2_RADIANS;
+// blon *= DEGREES_2_RADIANS;
+// return 2 * Math.asin(
+// Math.min(1, Math.sqrt(
+// Math.pow(Math.sin((blat-alat)/2), 2) +
+// (Math.cos(alat)*Math.cos(blat)*
+// Math.pow(
+// Math.sin((blon-alon)/2),2)
+// )
+// )
+// )
+// )
+// / DEGREES_2_RADIANS;
+//}
+//
+
+
+
+//This is a MEAN radius. The Earth is not perfectly spherical
+// public static final double EARTH_RADIUS_KM = 6371.0;
+// public static final double EARTH_RADIUS_NM = 3440.07;
+// public static final double KM_2_MILES_RATIO = 0.621371192;
+///**
+//* Code on Internet based on Unknown book. Lat/Long is in Degrees
+//* @param alat
+//* @param alon
+//* @param blat
+//* @param blon
+//* @return
+//*/
+//public static double calc1(double alat, double alon, double blat, double blon) {
+// alat *= DEGREES_2_RADIANS;
+// alon *= DEGREES_2_RADIANS;
+// blat *= DEGREES_2_RADIANS;
+// blon *= DEGREES_2_RADIANS;
+//
+// // Reused values
+// double cosAlat,cosBlat;
+//
+// return Math.acos(
+// ((cosAlat=Math.cos(alat))*Math.cos(alon)*(cosBlat=Math.cos(blat))*Math.cos(blon)) +
+// (cosAlat*Math.sin(alon)*cosBlat*Math.sin(blon)) +
+// (Math.sin(alat)*Math.sin(blat))
+// )/DEGREES_2_RADIANS;
+//
+//}
+
+/*
+* This method was 50% faster than calculation 1, and 75% than the Haverside method
+* Also, since it's based off of Agree standard Degrees of the Earth, etc, the calculations are more exact,
+* at least for Nautical Miles and Kilometers
+*/