/** * Copyright 2012 Comcast Corporation * * 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. */ package com.comcast.cns.model; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; import java.io.Writer; import org.apache.log4j.Logger; import org.json.JSONException; import org.json.JSONObject; /** * Class represents the retry policy. * @author jorge, bwolf * * Class is not thread-safe. Caller must ensure thread safety */ public class CNSRetryPolicy { private static Logger logger = Logger.getLogger(CNSRetryPolicy.class); public enum CnsBackoffFunction { linear, arithmetic, geometric, exponential;} private int minDelayTarget; private int maxDelayTarget; private int numRetries; private int numMaxDelayRetries; private int numMinDelayRetries; private int numNoDelayRetries; private CnsBackoffFunction backOffFunction; /* * Create an retryPolicy object by getting the variables directly */ public CNSRetryPolicy(int minDelayTarget, int maxDelayTarget, int numRetries, int numMaxDelayRetries, int numMinDelayRetries, int numNoDelayRetries, CnsBackoffFunction backoffFunction) { this.minDelayTarget = minDelayTarget; this.maxDelayTarget = maxDelayTarget; this.numRetries = numRetries; this.numMaxDelayRetries = numMaxDelayRetries; this.numMinDelayRetries = numMinDelayRetries; this.numNoDelayRetries = numNoDelayRetries; this.backOffFunction = backoffFunction; } /* * Create a default policy */ public CNSRetryPolicy() { this.minDelayTarget = 20; this.maxDelayTarget = 20; this.numRetries = 3; this.numMaxDelayRetries = 0; this.numMinDelayRetries = 0; this.numNoDelayRetries = 0; this.backOffFunction = CnsBackoffFunction.linear; } /** * Create a policy from a JSONObject * @param json The JSONObject that contains all the info for this Retry policy * @return the RetryPolicy formatted to default, or the parameter passed. */ public CNSRetryPolicy(JSONObject json) throws CNSModelConstructionException { boolean error = false; String message = ""; try { this.minDelayTarget = 20; this.maxDelayTarget = 20; this.numRetries = 3; this.numMaxDelayRetries = 0; this.numMinDelayRetries = 0; this.numNoDelayRetries = 0; this.backOffFunction = CnsBackoffFunction.linear; if (json.has("minDelayTarget")) { minDelayTarget = json.getInt("minDelayTarget"); } else { message = "minDelayTarget must be specified"; error = true; } if (json.has("maxDelayTarget")) { maxDelayTarget = json.getInt("maxDelayTarget"); } else { message = "maxDelayTarget must be specified"; error = true; } if (json.has("numRetries")) { numRetries = json.getInt("numRetries"); } else { message = "numRetries must be specified"; error = true; } if (json.has("numMaxDelayRetries")) { numMaxDelayRetries = json.getInt("numMaxDelayRetries"); } if (json.has("numMinDelayRetries")) { numMinDelayRetries = json.getInt("numMinDelayRetries"); } if (json.has("numNoDelayRetries")) { numNoDelayRetries = json.getInt("numNoDelayRetries"); } if (json.has("backoffFunction")) { String backoffFunctionStr = json.getString("backoffFunction"); try { backOffFunction = CnsBackoffFunction.valueOf(backoffFunctionStr); } catch (Exception e) { error = true; message = "invalid backoffFunction"; } } if (minDelayTarget > maxDelayTarget) { message ="maxDelayTarget must be greater than or equal to minDelayTarget"; error = true; } if (numRetries < numMaxDelayRetries + numMinDelayRetries + numNoDelayRetries) { message ="numRetries must be greater than or equal to total of numMinDelayRetries, numNoDelayRetries and numMaxDelayRetries"; error = true; } if (numRetries > 100) { message ="numRetries must be less than or equal to 100"; error = true; } if (numRetries < 0 || minDelayTarget < 0 || maxDelayTarget < 0 || numMaxDelayRetries < 0 || numMinDelayRetries < 0 || numNoDelayRetries < 0) { message ="all variables must be greater than or equal to 0"; error = true; } if (maxDelayTarget > 3600) { message ="max delay target must be less than or equal to 3600"; error = true; } } catch (JSONException e) { logger.error("event=construct_cns_retry_policy", e); throw new CNSModelConstructionException("JSON parameter format error"); } if (error) { logger.error("event=construct_cns_retry_policy message=" + message); throw new CNSModelConstructionException(message); } } private void update(Integer lminDelayTarget, Integer lmaxDelayTarget, Integer lnumRetries, Integer lnumMinDelayRetries, Integer lnumMaxDelayRetries, Integer lnumNoDelayRetries, CnsBackoffFunction lbackOffFunction) { this.minDelayTarget = lminDelayTarget; this.maxDelayTarget = lmaxDelayTarget; this.numRetries = lnumRetries; this.numMinDelayRetries = lnumMinDelayRetries; this.numMaxDelayRetries = lnumMaxDelayRetries; this.numNoDelayRetries = lnumNoDelayRetries; this.backOffFunction = lbackOffFunction; } /** * Update this object by taking values from parameter (if present) or the default values * Also do validation checks * @param json * @throws Exception */ public void update(JSONObject json) throws Exception { boolean error = false; String message = ""; try { //Reset the values to default, then set it to the new values Integer lminDelayTarget = 20; Integer lmaxDelayTarget = 20; Integer lnumRetries = 3; Integer lnumMinDelayRetries = 0; Integer lnumMaxDelayRetries = 0; Integer lnumNoDelayRetries = 0; CnsBackoffFunction lbackOffFunction = CnsBackoffFunction.linear; if (json.has("minDelayTarget")) { lminDelayTarget = json.getInt("minDelayTarget"); } else { message = "minDelayTarget must be specified"; error = true; } if (json.has("maxDelayTarget")) { lmaxDelayTarget = json.getInt("maxDelayTarget"); } else { message = "maxDelayTarget must be specified"; error = true; } if (json.has("numRetries")) { lnumRetries = json.getInt("numRetries"); } else { message = "numRetries must be specified"; error = true; } if (json.has("numMinDelayRetries")) { lnumMinDelayRetries = json.getInt("numMinDelayRetries"); } if (json.has("numMaxDelayRetries")) { lnumMaxDelayRetries = json.getInt("numMaxDelayRetries"); } if (json.has("numNoDelayRetries")) { lnumNoDelayRetries = json.getInt("numNoDelayRetries"); } if (json.has("backoffFunction")) { String backoffFunctionStr = json.getString("backoffFunction"); try { lbackOffFunction = CnsBackoffFunction.valueOf(backoffFunctionStr); } catch (Exception e) { error = true; message = "invalid backoffFunction"; } } if (!error) { if (lminDelayTarget > lmaxDelayTarget) { message ="maxDelayTarget must be greater than or equal to minDelayTarget"; error = true; } if (lnumRetries < lnumMaxDelayRetries + lnumMinDelayRetries + lnumNoDelayRetries) { message ="numRetries must be greater than or equal to total of numMinDelayRetries, numNoDelayRetries and numMaxDelayRetries"; error = true; } if (lnumRetries > 100) { message ="numRetries must be less than or equal to 100"; error = true; } if (lnumRetries < 0 || lminDelayTarget < 0 || lmaxDelayTarget < 0 || lnumMaxDelayRetries < 0 || lnumMinDelayRetries < 0 || lnumNoDelayRetries < 0) { message ="all variables must be greater than or equal to 0"; error = true; } if (lmaxDelayTarget > 3600) { message ="maxDelayTarget must be less than or equal to 3600"; error = true; } if (!error) { this.update(lminDelayTarget, lmaxDelayTarget, lnumRetries, lnumMinDelayRetries, lnumMaxDelayRetries, lnumNoDelayRetries, lbackOffFunction); } } } catch (Exception e) { logger.error("event=update_cns_retry_policy", e); throw new CNSModelConstructionException("JSON parameter format error"); } if (error) { logger.error("event=update_cns_retry_policy message=" + message); throw new CNSModelConstructionException(message); } } public int getMinDelayTarget() { return minDelayTarget; } public void setMinDelayTarget(int minDelayTarget) { this.minDelayTarget = minDelayTarget; } public int getMaxDelayTarget() { return maxDelayTarget; } public void setMaxDelayTarget(int maxDelayTarget) { this.maxDelayTarget = maxDelayTarget; } public int getNumRetries() { return numRetries; } public void setNumRetries(int numRetries) { this.numRetries = numRetries; } public int getNumMaxDelayRetries() { return numMaxDelayRetries; } public void setNumMaxDelayRetries(int numMaxDelayRetries) { this.numMaxDelayRetries = numMaxDelayRetries; } public CnsBackoffFunction getBackOffFunction() { return backOffFunction; } public void setBackOffFunction(CnsBackoffFunction backOffFunction) { this.backOffFunction = backOffFunction; } public JSONObject toJSON() { try { JSONObject json = new JSONObject(); json.put("minDelayTarget", minDelayTarget); json.put("maxDelayTarget", maxDelayTarget); json.put("numRetries", numRetries); json.put("numMaxDelayRetries", numMaxDelayRetries); json.put("numMinDelayRetries", numMinDelayRetries); json.put("numNoDelayRetries", numNoDelayRetries); json.put("backoffFunction", backOffFunction.toString()); return json; } catch (Exception e) { logger.error("event=cns_retry_policy_to_json", e); } return null; } @Override public String toString() { try { JSONObject json = this.toJSON(); ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer writer = new PrintWriter(out); json.write(writer); writer.flush(); return out.toString(); } catch (Exception e) { return null; } } public int getNumMinDelayRetries() { return numMinDelayRetries; } public void setNumMinDelayRetries(int numMinDelayRetries) { this.numMinDelayRetries = numMinDelayRetries; } public int getNumNoDelayRetries() { return numNoDelayRetries; } public void setNumNoDelayRetries(int numNoDelayRetries) { this.numNoDelayRetries = numNoDelayRetries; } }