From 6aef64a3ad6322a74ef0116028b28e3f01c06bb6 Mon Sep 17 00:00:00 2001 From: Roman Sutormin Date: Mon, 13 Jun 2016 17:19:13 -0700 Subject: [PATCH 1/2] Support for dynamic clients in java common JSON RPC client code. --- .../common/service/JsonClientCaller.java | 96 ++++++++++++++++--- 1 file changed, 81 insertions(+), 15 deletions(-) diff --git a/src/us/kbase/common/service/JsonClientCaller.java b/src/us/kbase/common/service/JsonClientCaller.java index 041fb9a..7eca410 100644 --- a/src/us/kbase/common/service/JsonClientCaller.java +++ b/src/us/kbase/common/service/JsonClientCaller.java @@ -15,6 +15,7 @@ import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.*; +import java.util.regex.Pattern; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -38,7 +39,8 @@ public class JsonClientCaller { public final URL serviceUrl; - private ObjectMapper mapper; + private static final ObjectMapper mapper = new ObjectMapper().registerModule( + new JacksonTupleModule());; private String user = null; private char[] password = null; private AuthToken accessToken = null; @@ -47,6 +49,8 @@ public class JsonClientCaller { private boolean streamRequest = false; private Integer connectionReadTimeOut = 30 * 60 * 1000; private File fileForNextRpcResponse = null; + private boolean isDynamic = false; + private final URL authServiceUrl; private static TrustManager[] GULLIBLE_TRUST_MGR = new TrustManager[] { @@ -74,7 +78,6 @@ public JsonClientCaller(URL url) { public JsonClientCaller(URL url, URL authServiceUrl) { serviceUrl = url; - mapper = new ObjectMapper().registerModule(new JacksonTupleModule()); this.authServiceUrl = authServiceUrl; } @@ -187,7 +190,18 @@ public void setConnectionReadTimeOut(Integer connectionReadTimeOut) { this.connectionReadTimeOut = connectionReadTimeOut; } - private HttpURLConnection setupCall(boolean authRequired) throws IOException, JsonClientException { + public boolean isDynamic() { + return isDynamic; + } + + public void setDynamic(boolean isDynamic) { + this.isDynamic = isDynamic; + } + + private static HttpURLConnection setupCall(URL serviceUrl, boolean authRequired, + Integer connectionReadTimeOut, JsonClientCaller accessTokenHolder, + boolean allowInsecureHttp, String user, char[] password, URL authServiceUrl, + boolean trustAllCerts) throws IOException, JsonClientException { HttpURLConnection conn = (HttpURLConnection) serviceUrl.openConnection(); conn.setConnectTimeout(10000); if (connectionReadTimeOut != null) { @@ -195,15 +209,15 @@ private HttpURLConnection setupCall(boolean authRequired) throws IOException, Js } conn.setDoOutput(true); conn.setRequestMethod("POST"); - if (authRequired || accessToken != null) { + if (authRequired || accessTokenHolder.accessToken != null) { if (!(conn instanceof HttpsURLConnection || allowInsecureHttp)) { throw new UnauthorizedException("RPC method required authentication shouldn't " + "be called through unsecured http, use https instead or call " + "setAuthAllowedForHttp(true) for your client"); } - if (accessToken == null || accessToken.isExpired()) { + if (accessTokenHolder.accessToken == null || accessTokenHolder.accessToken.isExpired()) { if (user == null) { - if (accessToken == null) { + if (accessTokenHolder.accessToken == null) { throw new UnauthorizedException("RPC method requires authentication but neither " + "user nor token was set"); } else { @@ -211,9 +225,9 @@ private HttpURLConnection setupCall(boolean authRequired) throws IOException, Js "because user wasn't set"); } } - accessToken = requestTokenFromKBase(user, password, authServiceUrl); + accessTokenHolder.accessToken = requestTokenFromKBase(user, password, authServiceUrl); } - conn.setRequestProperty("Authorization", accessToken.toString()); + conn.setRequestProperty("Authorization", accessTokenHolder.accessToken.toString()); } if (conn instanceof HttpsURLConnection && trustAllCerts) { final HttpsURLConnection hc = (HttpsURLConnection) conn; @@ -270,14 +284,62 @@ public RET jsonrpcCall(String method, ARG arg, TypeReference cls public RET jsonrpcCall(String method, ARG arg, TypeReference cls, boolean ret, boolean authRequired, RpcContext[] context) throws IOException, JsonClientException { + return jsonrpcCall(method, arg, cls, ret, authRequired, context, null); + } + + public RET jsonrpcCall(String method, ARG arg, TypeReference cls, + boolean ret, boolean authRequired, RpcContext[] context, String serviceVersion) + throws IOException, JsonClientException { return jsonrpcCall(method, arg, cls, ret, authRequired, - context != null && context.length == 1 ? context[0] : null); + context != null && context.length == 1 ? context[0] : null, serviceVersion); + } + + public RET jsonrpcCall(String method, ARG arg, TypeReference cls, + boolean ret, boolean authRequired, RpcContext context) + throws IOException, JsonClientException { + return jsonrpcCall(method, arg, cls, ret, authRequired, context, null); } public RET jsonrpcCall(String method, ARG arg, TypeReference cls, - boolean ret, boolean authRequired, RpcContext context) + boolean ret, boolean authRequired, RpcContext context, String serviceVersion) throws IOException, JsonClientException { - HttpURLConnection conn = setupCall(authRequired); + URL url; + if (isDynamic) { + String serviceModuleName = method.split(Pattern.quote("."))[0]; + List serviceStatusArgs = new ArrayList(); + Map serviceStruct = new LinkedHashMap(); + serviceStruct.put("module_name", serviceModuleName); + serviceStruct.put("version", serviceVersion); + serviceStatusArgs.add(serviceStruct); + List> serviceState = jsonrpcCallStatic(serviceUrl, + "ServiceWizard.get_service_status", serviceStatusArgs, + new TypeReference>>() {}, ret, + false, null, streamRequest, connectionReadTimeOut, + this, allowInsecureHttp, user, password, authServiceUrl, + trustAllCerts, null); + url = new URL((String)serviceState.get(0).get("url")); + } else { + url = serviceUrl; + } + try { + return jsonrpcCallStatic(url, method, arg, cls, ret, authRequired, + context, streamRequest, connectionReadTimeOut, + this, allowInsecureHttp, user, password, authServiceUrl, + trustAllCerts, fileForNextRpcResponse); + } finally { + fileForNextRpcResponse = null; + } + } + + private static RET jsonrpcCallStatic(URL serviceUrl, String method, ARG arg, + TypeReference cls, boolean ret, boolean authRequired, RpcContext context, + boolean streamRequest, Integer connectionReadTimeOut, + JsonClientCaller accessTokenHolder, boolean allowInsecureHttp, String user, + char[] password, URL authServiceUrl, boolean trustAllCerts, + File fileForNextRpcResponse) throws IOException, JsonClientException { + HttpURLConnection conn = setupCall(serviceUrl, authRequired, connectionReadTimeOut, + accessTokenHolder, allowInsecureHttp, user, password, authServiceUrl, + trustAllCerts); String id = ("" + Math.random()).replace(".", ""); if (streamRequest) { // Calculate content-length before @@ -286,7 +348,7 @@ public RET jsonrpcCall(String method, ARG arg, TypeReference cls conn.setFixedLengthStreamingMode(size); } // Write real data into http output stream - writeRequestData(method, arg, conn.getOutputStream(), id, context); + writeRequestDataStatic(method, arg, conn.getOutputStream(), id, context); // Read response int code = conn.getResponseCode(); conn.getResponseMessage(); @@ -380,7 +442,6 @@ public RET jsonrpcCall(String method, ARG arg, TypeReference cls throw new ServerException("An unknown server error occured", 0, "Unknown", null); } } finally { - fileForNextRpcResponse = null; if (fos != null) try { fos.close(); @@ -389,7 +450,7 @@ public RET jsonrpcCall(String method, ARG arg, TypeReference cls } } - private long calculateResponseLength(String method, ARG arg, + private static long calculateResponseLength(String method, ARG arg, String id, RpcContext context) throws IOException { final long[] sizeWrapper = new long[] {0}; OutputStream os = new OutputStream() { @@ -400,7 +461,7 @@ private long calculateResponseLength(String method, ARG arg, @Override public void write(byte[] b, int o, int l) {sizeWrapper[0] += l;} }; - writeRequestData(method, arg, os, id, context); + writeRequestDataStatic(method, arg, os, id, context); return sizeWrapper[0]; } @@ -422,6 +483,11 @@ private static void checkToken(JsonToken expected, JsonToken actual) throws Json public void writeRequestData(String method, Object arg, OutputStream os, String id, RpcContext context) throws IOException { + writeRequestDataStatic(method, arg, os, id, context); + } + + private static void writeRequestDataStatic(String method, Object arg, OutputStream os, String id, + RpcContext context) throws IOException { JsonGenerator g = mapper.getFactory().createGenerator(os, JsonEncoding.UTF8); g.writeStartObject(); g.writeObjectField("params", arg); From 0111c732b134e6c52e089117eab39fafa68ef0ba Mon Sep 17 00:00:00 2001 From: Roman Sutormin Date: Tue, 14 Jun 2016 11:33:44 -0700 Subject: [PATCH 2/2] Release notes are updated. --- RELEASE_NOTES.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 7160ccb..e8634d5 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -4,6 +4,20 @@ OVERVIEW ----------------------------------------- Repo for code shared between Java services. + +VERSION: 0.0.17 (Released 6/14/2016) +-------------------------------------- + +NEW FEATURES: +- None + +UPDATED FEATURES / MAJOR BUG FIXES: +- Support for dynamic Java client URL lookup is added to JsonClientCaller + +ANTICIPATED FUTURE DEVELOPMENTS: +- None + + VERSION: 0.0.16 (Released 6/13/2016) -------------------------------------- @@ -19,6 +33,7 @@ UPDATED FEATURES / MAJOR BUG FIXES: ANTICIPATED FUTURE DEVELOPMENTS: - None + VERSION: 0.0.15 (Released 1/24/2015) -------------------------------------- @@ -32,6 +47,7 @@ UPDATED FEATURES / MAJOR BUG FIXES: ANTICIPATED FUTURE DEVELOPMENTS: - None + VERSION: 0.0.14 (Released 1/4/2015) --------------------------------------