001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.synapse.endpoints.algorithms;
020:
021: import org.apache.axis2.clustering.ClusteringFault;
022: import org.apache.axis2.clustering.context.Replicator;
023: import org.apache.axis2.context.ConfigurationContext;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.apache.synapse.SynapseException;
027:
028: /**
029: * Keeps the states of the load balance algorithm.This hides where those states are kept.For a
030: * cluster environment ,all states are kept in the axis2 configuration context in order to replicate
031: * those states so that other synapse instance in the same cluster can see those changes .
032: * This class can be evolved to keep any run time states related to the endpoint .
033: * For a non-clustered environment , all data are kept locally.
034: * <p/>
035: * This class provide the abstraction need to separate the dynamic data from the static data
036: * and improve the high cohesion and provides capability to replicate only required state at
037: * a given time. This improves the performance when replicate data.
038: */
039: public class AlgorithmContext {
040:
041: private static final Log log = LogFactory
042: .getLog(AlgorithmContext.class);
043:
044: /* The static constant only for construct key prefix for each property in a dispatcher context
045: * as it is need when those property state going to replicate in a cluster env. */
046: private static final String UNDERSCORE_STRING = "_";
047: private static final String CURRENT_EPR = "currentEPR";
048:
049: /*The axis configuration context- this will hold the all callers states
050: *when doing throttling in a clustered environment. */
051: private ConfigurationContext configCtx;
052:
053: /* Is this env. support clustering*/
054: private boolean isClusteringEnable = false;
055:
056: /*The key for 'currentEPR' attribute and this is used when this attribute value being replicated */
057: private String currentEPRPropertyKey;
058:
059: /*The pointer to current epr - The position of the current EPR */
060: private int currentEPR = 0;
061:
062: /**
063: * To get the position of the current EPR
064: * If there is no value and if there will not appear any errors , then '0' will be returned.
065: *
066: * @return The position of the current EPR
067: */
068: public int getCurrentEndpointIndex() {
069:
070: if (this .isClusteringEnable) { // if this is a clustering env.
071:
072: if (this .currentEPRPropertyKey == null
073: || "".equals(this .currentEPRPropertyKey)) {
074: handleException("Cannot find the required key to find the "
075: + "shared state of the 'currentEPR' attribute");
076: }
077:
078: Object value = this .configCtx
079: .getPropertyNonReplicable(this .currentEPRPropertyKey);
080: if (value == null) {
081: return 0;
082: }
083: try {
084: if (value instanceof Integer) {
085: return ((Integer) value).intValue();
086: } else if (value instanceof String) {
087: return Integer.parseInt((String) value);
088: }
089: } catch (NumberFormatException e) {
090: handleException("The invalid value for the 'currentEPR' attribute");
091: }
092: } else {
093: return currentEPR;
094: }
095: return 0;
096: }
097:
098: /**
099: * The position of the current EPR
100: *
101: * @param currentEPR The current position
102: */
103: public void setCurrentEPR(int currentEPR) {
104:
105: if (isClusteringEnable) { // if this is a clustering env.
106:
107: if (currentEPRPropertyKey != null) {
108: // Sets the property and replicates the current state so that all instances
109: setAndReplicateState(currentEPRPropertyKey, currentEPR);
110: }
111: } else {
112: this .currentEPR = currentEPR;
113: }
114: }
115:
116: /**
117: * Get the configuration context instance . This is only available for cluster env.
118: *
119: * @return Returns the ConfigurationContext instance
120: */
121: public ConfigurationContext getConfigurationContext() {
122: return configCtx;
123: }
124:
125: /**
126: * Sets the ConfigurationContext instance . This is only used for cluster env.
127: * By setting this , indicates that this is a cluster env.
128: *
129: * @param configCtx The ConfigurationContext instance
130: */
131: public void setConfigurationContext(ConfigurationContext configCtx) {
132:
133: if (configCtx == null) {
134: handleException("The ConfigurationContext cannot be null when system "
135: + "in a cluster environment");
136: }
137:
138: this .configCtx = configCtx;
139: this .isClusteringEnable = true; // Now, the environment is considered as a cluster
140: }
141:
142: /**
143: * Sets the identifier for this algorithm context , so that , this can be identified
144: * uniquely across the cluster. The id will be the name of the endpoint
145: *
146: * @param contextID The Id for this algorithm context
147: */
148: public void setContextID(String contextID) {
149:
150: if (contextID == null || "".equals(contextID)) {
151: handleException("The Context ID cannot be null when system in a cluster environment");
152: }
153:
154: //Making required key for each property in the algorithm context- Those will be used when
155: //replicating states
156: StringBuffer buffer = new StringBuffer();
157: buffer.append(contextID);
158: buffer.append(UNDERSCORE_STRING);
159: buffer.append(CURRENT_EPR);
160: currentEPRPropertyKey = buffer.toString();
161:
162: }
163:
164: /**
165: * Helper methods for handle errors.
166: *
167: * @param msg The error message
168: */
169: protected void handleException(String msg) {
170:
171: log.error(msg);
172: throw new SynapseException(msg);
173: }
174:
175: /**
176: * Helper methods for handle errors.
177: *
178: * @param msg The error message
179: * @param e The exception
180: */
181: protected void handleException(String msg, Exception e) {
182:
183: log.error(msg, e);
184: throw new SynapseException(msg, e);
185: }
186:
187: /**
188: * Helper method to replicates states of the property with given key
189: * Sets property and replicates the current state so that all instances
190: * across cluster can see this state
191: *
192: * @param key The key of the property
193: * @param value The value of the property
194: */
195: private void setAndReplicateState(String key, Object value) {
196:
197: if (configCtx != null && key != null && value != null) {
198:
199: try {
200: if (log.isDebugEnabled()) {
201: log
202: .debug("Going to replicate the property with key : "
203: + key + " value : " + value);
204: }
205:
206: configCtx.setProperty(key, value);
207: Replicator.replicate(configCtx, new String[] { key });
208:
209: } catch (ClusteringFault clusteringFault) {
210: handleException("Error during the replicating states ",
211: clusteringFault);
212: }
213: }
214: }
215:
216: }
|