/** * Alipay.com Inc. * Copyright (c) 2004-2012 All Rights Reserved. */ package com.alipay.zdal.common; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.log4j.Logger; /** * * @author ���� * @version $Id: WeightRandom.java, v 0.1 2014-1-6 ����05:17:44 Exp $ */ public class WeightRandom { private static final Logger logger = Logger .getLogger(WeightRandom.class); public static final int DEFAULT_WEIGHT_NEW_ADD = 0; public static final int DEFAULT_WEIGHT_INIT = 10; private Map<String, Integer> cachedWeightConfig; private final RuntimeConfigHolder<Weight> weightHolder = new RuntimeConfigHolder<Weight>(); /** * ���ֲ������ֻ���ؽ��������޸� */ private static class Weight { public Weight(int[] weights, String[] weightKeys, int[] weightAreaEnds) { this.weightKeys = weightKeys; this.weightValues = weights; this.weightAreaEnds = weightAreaEnds; } public final String[] weightKeys; //�����߱�֤�����޸���Ԫ�� public final int[] weightValues; //�����߱�֤�����޸���Ԫ�� public final int[] weightAreaEnds; //�����߱�֤�����޸���Ԫ�� } public WeightRandom(Map<String, Integer> weightConfigs) { this.init(weightConfigs); } public WeightRandom(String[] keys) { Map<String, Integer> weightConfigs = new HashMap<String, Integer>(keys.length); for (String key : keys) { weightConfigs.put(key, DEFAULT_WEIGHT_INIT); } this.init(weightConfigs); } private void init(Map<String, Integer> weightConfig) { this.cachedWeightConfig = weightConfig; String[] weightKeys = weightConfig.keySet().toArray(new String[0]); int[] weights = new int[weightConfig.size()]; for (int i = 0; i < weights.length; i++) { weights[i] = weightConfig.get(weightKeys[i]); } int[] weightAreaEnds = genAreaEnds(weights); weightHolder.set(new Weight(weights, weightKeys, weightAreaEnds)); } /** * ֧�ֶ�̬�޸� */ public void setWeightConfig(Map<String, Integer> weightConfig) { this.init(weightConfig); } public Map<String, Integer> getWeightConfig() { return this.cachedWeightConfig; } /** * ����������Ȩ�� 10 9 8 * ��ôareaEnds���� 10 19 27 * �������0~27֮���һ���� * * �ֱ�ȥ����areaEnds���Ԫ�رȡ� * * ���������С��һ��Ԫ���ˣ����ʾӦ��ѡ�����Ԫ�� * * ע�⣺�÷������ܸı������������ */ private final Random random = new Random(); private String select(int[] areaEnds, String[] keys) { int sum = areaEnds[areaEnds.length - 1]; if (sum == 0) { logger.error("areaEnds: " + intArray2String(areaEnds)); return null; } //ѡ��Ĺ� //findbugs��Ϊ���ﲻ�Ǻܺ�(ÿ�ζ��½�һ��Random)(guangxia) int rand = random.nextInt(sum); for (int i = 0; i < areaEnds.length; i++) { if (rand < areaEnds[i]) { return keys[i]; } } return null; } /** * ͨ������Դ�ı�ʶ��ȡ��Ӧ��Ȩ�أ� * @param key * @return */ public int getWeightByKey(String key) { int weight = 0; boolean flag = false; final Weight w = weightHolder.get(); for (int k = 0; k < w.weightKeys.length; k++) { if (w.weightKeys[k].equals(key)) { flag = true; weight = w.weightValues[k]; } } if (flag == false) { logger.error("����Դ�ı�ʶ�����ڣ��Ƿ���key=" + key); } return weight; } /** * @param excludeKeys ��Ҫ�ų���key�б� * @return */ public String select(List<String> excludeKeys) { final Weight w = weightHolder.get(); //����ʵ�ֱ�֤���ܸı�w���κ���������ݣ������̲߳���ȫ if (excludeKeys == null || excludeKeys.isEmpty()) { return select(w.weightAreaEnds, w.weightKeys); } int[] tempWeights = w.weightValues.clone(); for (int k = 0; k < w.weightKeys.length; k++) { if (excludeKeys.contains(w.weightKeys[k])) { tempWeights[k] = 0; } } int[] tempAreaEnd = genAreaEnds(tempWeights); return select(tempAreaEnd, w.weightKeys); } public static interface Tryer<T extends Throwable> { /** * @return null��ʾ�ɹ������򷵻�һ���쳣 */ public T tryOne(String name); } /** * @return null��ʾ�ɹ������򷵻�һ���쳣�б� */ public <T extends Throwable> List<T> retry(int times, Tryer<T> tryer) { List<T> exceptions = new ArrayList<T>(0); List<String> excludeKeys = new ArrayList<String>(0); for (int i = 0; i < times; i++) { String name = this.select(excludeKeys); T e = tryer.tryOne(name); if (e != null) { exceptions.add(e); excludeKeys.add(name); } else { return null; } } return exceptions; } public <T extends Throwable> List<T> retry(Tryer<T> tryer) { return retry(3, tryer); } private static int[] genAreaEnds(int[] weights) { if (weights == null) { return null; } int[] areaEnds = new int[weights.length]; int sum = 0; for (int i = 0; i < weights.length; i++) { sum += weights[i]; areaEnds[i] = sum; } if (logger.isDebugEnabled()) { logger.debug("generate " + intArray2String(areaEnds) + " from " + intArray2String(weights)); } if (sum == 0) { logger.warn("generate " + intArray2String(areaEnds) + " from " + intArray2String(weights)); } return areaEnds; } private static String intArray2String(int[] inta) { if (inta == null) { return "null"; } else if (inta.length == 0) { return "[]"; } StringBuilder sb = new StringBuilder(); sb.append("[").append(inta[0]); for (int i = 1; i < inta.length; i++) { sb.append(", ").append(inta[i]); } sb.append("]"); return sb.toString(); } public String getAllDbKeys() { StringBuilder sb = new StringBuilder(); final Weight w = weightHolder.get(); sb.append("[").append(w.weightKeys[0]); for (int i = 1; i < w.weightKeys.length; i++) { sb.append(",").append(w.weightKeys[i]); } sb.append("]"); return sb.toString(); } }