1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 package org.apache.synapse.endpoints.algorithms; 20 21 import org.apache.axis2.clustering.ClusteringFault; 22 import org.apache.axis2.clustering.context.Replicator; 23 import org.apache.axis2.context.ConfigurationContext; 24 import org.apache.commons.logging.Log; 25 import org.apache.commons.logging.LogFactory; 26 import org.apache.synapse.SynapseException; 27 28 /** 29 * Keeps the states of the load balance algorithm.This hides where those states are kept.For a 30 * cluster environment ,all states are kept in the axis2 configuration context in order to replicate 31 * those states so that other synapse instance in the same cluster can see those changes . 32 * This class can be evolved to keep any run time states related to the endpoint . 33 * For a non-clustered environment , all data are kept locally. 34 * <p/> 35 * This class provide the abstraction need to separate the dynamic data from the static data 36 * and improve the high cohesion and provides capability to replicate only required state at 37 * a given time. This improves the performance when replicate data. 38 */ 39 public class AlgorithmContext { 40 41 private static final Log log = LogFactory.getLog(AlgorithmContext.class); 42 43 /* The static constant only for construct key prefix for each property in a dispatcher context 44 * as it is need when those property state going to replicate in a cluster env. */ 45 private static final String UNDERSCORE_STRING = "_"; 46 private static final String CURRENT_EPR = "currentEPR"; 47 48 /* The axis configuration context- this will hold the all callers states 49 * when doing throttling in a clustered environment. */ 50 private ConfigurationContext configCtx; 51 52 /* Is this env. support clustering*/ 53 private boolean isClusteringEnable = false; 54 55 /* The key for 'currentEPR' attribute and this is used when this attribute value being 56 * replicated */ 57 private String currentEPRPropertyKey; 58 59 /* The pointer to current epr - The position of the current EPR */ 60 private int currentEPR = 0; 61 62 /** 63 * To get the position of the current EPR 64 * If there is no value and if there will not appear any errors , then '0' will be returned. 65 * 66 * @return The position of the current EPR 67 */ 68 public int getCurrentEndpointIndex() { 69 70 if (this.isClusteringEnable) { // if this is a clustering env. 71 72 if (this.currentEPRPropertyKey == null || "".equals(this.currentEPRPropertyKey)) { 73 handleException("Cannot find the required key to find the " + 74 "shared state of the 'currentEPR' attribute"); 75 } 76 77 Object value = this.configCtx.getPropertyNonReplicable(this.currentEPRPropertyKey); 78 if (value == null) { 79 return 0; 80 } 81 try { 82 if (value instanceof Integer) { 83 return ((Integer) value).intValue(); 84 } else if (value instanceof String) { 85 return Integer.parseInt((String) value); 86 } 87 } catch (NumberFormatException e) { 88 handleException("The invalid value for the 'currentEPR' attribute"); 89 } 90 } else { 91 return currentEPR; 92 } 93 return 0; 94 } 95 96 /** 97 * The position of the current EPR 98 * 99 * @param currentEPR The current position 100 */ 101 public void setCurrentEPR(int currentEPR) { 102 103 if (isClusteringEnable) { // if this is a clustering env. 104 105 if (currentEPRPropertyKey != null) { 106 if (log.isDebugEnabled()) { 107 log.debug("Setting the current EPR " + currentEPR 108 + " with the key " + currentEPRPropertyKey); 109 } 110 // Sets the property and replicates the current state so that all instances 111 setAndReplicateState(currentEPRPropertyKey, currentEPR); 112 } 113 } else { 114 if (log.isDebugEnabled()) { 115 log.debug("Setting the current EPR " + currentEPR); 116 } 117 this.currentEPR = currentEPR; 118 } 119 } 120 121 /** 122 * Get the configuration context instance . This is only available for cluster env. 123 * 124 * @return Returns the ConfigurationContext instance 125 */ 126 public ConfigurationContext getConfigurationContext() { 127 return configCtx; 128 } 129 130 /** 131 * Sets the ConfigurationContext instance . This is only used for cluster env. 132 * By setting this , indicates that this is a cluster env. 133 * 134 * @param configCtx The ConfigurationContext instance 135 */ 136 public void setConfigurationContext(ConfigurationContext configCtx) { 137 138 if (configCtx == null) { 139 handleException("The ConfigurationContext cannot be null when system " + 140 "in a cluster environment"); 141 } 142 143 this.configCtx = configCtx; 144 this.isClusteringEnable = true; // Now, the environment is considered as a cluster 145 } 146 147 /** 148 * Sets the identifier for this algorithm context , so that , this can be identified 149 * uniquely across the cluster. The id will be the name of the endpoint 150 * 151 * @param contextID The Id for this algorithm context 152 */ 153 public void setContextID(String contextID) { 154 155 if (contextID == null || "".equals(contextID)) { 156 handleException("The Context ID cannot be null when system in a cluster environment"); 157 } 158 159 //Making required key for each property in the algorithm context- Those will be used when 160 //replicating states 161 StringBuffer buffer = new StringBuffer(); 162 buffer.append(contextID); 163 buffer.append(UNDERSCORE_STRING); 164 buffer.append(CURRENT_EPR); 165 currentEPRPropertyKey = buffer.toString(); 166 } 167 168 169 /** 170 * Helper methods for handle errors. 171 * 172 * @param msg The error message 173 */ 174 protected void handleException(String msg) { 175 log.error(msg); 176 throw new SynapseException(msg); 177 } 178 179 /** 180 * Helper methods for handle errors. 181 * 182 * @param msg The error message 183 * @param e The exception 184 */ 185 protected void handleException(String msg, Exception e) { 186 log.error(msg, e); 187 throw new SynapseException(msg, e); 188 } 189 190 /** 191 * Helper method to replicates states of the property with given key 192 * Sets property and replicates the current state so that all instances 193 * across cluster can see this state 194 * 195 * @param key The key of the property 196 * @param value The value of the property 197 */ 198 private void setAndReplicateState(String key, Object value) { 199 200 if (configCtx != null && key != null && value != null) { 201 202 try { 203 if (log.isDebugEnabled()) { 204 log.debug("Start replicating the property with key : " + key 205 + " value : " + value); 206 } 207 208 configCtx.setProperty(key, value); 209 Replicator.replicate(configCtx, new String[]{key}); 210 211 if (log.isDebugEnabled()) { 212 log.debug("Completed replication of the property with key : " + key); 213 } 214 215 } catch (ClusteringFault clusteringFault) { 216 handleException("Error during the replicating states ", clusteringFault); 217 } 218 } 219 } 220 221 }