001 /* 002 * JBoss, Home of Professional Open Source. 003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors 004 * as indicated by the @author tags. See the copyright.txt file in the 005 * distribution for a full listing of individual contributors. 006 * 007 * This is free software; you can redistribute it and/or modify it 008 * under the terms of the GNU Lesser General Public License as 009 * published by the Free Software Foundation; either version 2.1 of 010 * the License, or (at your option) any later version. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this software; if not, write to the Free 019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 021 */ 022 package org.jboss.dna.connector.federation.contribution; 023 024 import java.util.Collections; 025 import java.util.HashMap; 026 import java.util.LinkedList; 027 import java.util.List; 028 import java.util.Map; 029 import java.util.concurrent.ConcurrentHashMap; 030 import java.util.concurrent.ConcurrentMap; 031 import java.util.concurrent.atomic.AtomicLong; 032 import org.jboss.dna.common.util.CheckArg; 033 import org.jboss.dna.common.util.HashCode; 034 035 /** 036 * Simple utility class to record the distribution of contributions. 037 * 038 * @author Randall Hauch 039 */ 040 public class ContributionStatistics { 041 042 /** 043 * This should only be enabled when attempting to accumulate the distribution, and should <i>never</i> be enabled in a 044 * release. 045 */ 046 /*package*/static final boolean RECORD = false; 047 048 private static final ConcurrentMap<Stats, AtomicLong> DATA = new ConcurrentHashMap<Stats, AtomicLong>(); 049 050 /** 051 * Record a {@link Contribution} was created for the supplied number of properties and children. {@link #RECORD} should be 052 * checked <i>before</i> this method is called. 053 * 054 * @param propertyCount the number of properties 055 * @param childrenCount the number of children 056 */ 057 /*package*/static void record( int propertyCount, 058 int childrenCount ) { 059 Stats key = new Stats(propertyCount, childrenCount); 060 AtomicLong existing = DATA.putIfAbsent(key, new AtomicLong(1l)); 061 if (existing != null) existing.incrementAndGet(); 062 } 063 064 public boolean isRecording() { 065 return RECORD; 066 } 067 068 /** 069 * Get a copy of the raw statistics data. 070 * 071 * @return a copy of the data; never null 072 */ 073 public static Map<Stats, AtomicLong> getData() { 074 return new HashMap<Stats, AtomicLong>(DATA); 075 } 076 077 /** 078 * Get the N most populous combinations of properties and children counts. 079 * 080 * @param n the maximum number of data objects to find and return in the raw data; must be positive 081 * @return the list of N (or fewer) 082 */ 083 public static List<Data> getTop( int n ) { 084 CheckArg.isPositive(n, "n"); 085 LinkedList<Data> results = new LinkedList<Data>(); 086 for (Map.Entry<Stats, AtomicLong> entry : DATA.entrySet()) { 087 long value = entry.getValue().get(); 088 if (results.size() >= n) { 089 Data last = results.getLast(); 090 if (value <= last.getInstanceCount()) continue; 091 // The new count is larger than the smallest, so pop the smallest and add the newest ... 092 results.removeLast(); 093 } 094 results.add(new Data(entry.getKey(), value)); 095 Collections.sort(results); 096 } 097 return results; 098 } 099 100 public static final class Data implements Comparable<Data> { 101 private final int propertyCount; 102 private final int childrenCount; 103 private final long instanceCount; 104 105 protected Data( Stats stats, 106 long instanceCount ) { 107 this.propertyCount = stats.getPropertyCount(); 108 this.childrenCount = stats.getChildrenCount(); 109 this.instanceCount = instanceCount; 110 } 111 112 /** 113 * @return childrenCount 114 */ 115 public int getChildrenCount() { 116 return childrenCount; 117 } 118 119 /** 120 * @return propertyCount 121 */ 122 public int getPropertyCount() { 123 return propertyCount; 124 } 125 126 /** 127 * @return instanceCount 128 */ 129 public long getInstanceCount() { 130 return instanceCount; 131 } 132 133 /** 134 * {@inheritDoc} This orders the values in the opposite order, so that those with larger numbers of instances appear 135 * first. 136 * 137 * @see java.lang.Comparable#compareTo(java.lang.Object) 138 */ 139 public int compareTo( Data that ) { 140 long diff = that.getInstanceCount() - this.getInstanceCount(); // backwards 141 return diff < 0l ? -1 : diff > 0 ? 1 : 0; 142 } 143 144 /** 145 * {@inheritDoc} 146 * 147 * @see java.lang.Object#hashCode() 148 */ 149 @Override 150 public int hashCode() { 151 return HashCode.compute(this.propertyCount, this.childrenCount, this.instanceCount); 152 } 153 154 /** 155 * {@inheritDoc} 156 * 157 * @see java.lang.Object#equals(java.lang.Object) 158 */ 159 @Override 160 public boolean equals( Object obj ) { 161 if (obj instanceof Data) { 162 Data that = (Data)obj; 163 if (this.propertyCount != that.propertyCount) return false; 164 if (this.childrenCount != that.childrenCount) return false; 165 if (this.instanceCount != that.instanceCount) return false; 166 return true; 167 } 168 return false; 169 } 170 171 /** 172 * {@inheritDoc} 173 * 174 * @see java.lang.Object#toString() 175 */ 176 @Override 177 public String toString() { 178 return "(# props=" + this.getPropertyCount() + ", # children=" + this.getChildrenCount() + ") => " 179 + this.getInstanceCount(); 180 } 181 } 182 183 public static final class Stats { 184 private final int propertyCount; 185 private final int childrenCount; 186 187 protected Stats( int propertyCount, 188 int childrenCount ) { 189 this.propertyCount = propertyCount; 190 this.childrenCount = childrenCount; 191 } 192 193 /** 194 * @return childrenCount 195 */ 196 public int getChildrenCount() { 197 return childrenCount; 198 } 199 200 /** 201 * @return propertyCount 202 */ 203 public int getPropertyCount() { 204 return propertyCount; 205 } 206 207 /** 208 * {@inheritDoc} 209 * 210 * @see java.lang.Object#hashCode() 211 */ 212 @Override 213 public int hashCode() { 214 return HashCode.compute(this.propertyCount, this.childrenCount); 215 } 216 217 /** 218 * {@inheritDoc} 219 * 220 * @see java.lang.Object#equals(java.lang.Object) 221 */ 222 @Override 223 public boolean equals( Object obj ) { 224 if (obj instanceof Stats) { 225 Stats that = (Stats)obj; 226 if (this.propertyCount != that.propertyCount) return false; 227 if (this.childrenCount != that.childrenCount) return false; 228 return true; 229 } 230 return false; 231 } 232 } 233 234 }