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: */
020: package org.apache.mina.filter.executor;
021:
022: import java.lang.reflect.Field;
023: import java.lang.reflect.Modifier;
024: import java.util.HashSet;
025: import java.util.Set;
026: import java.util.concurrent.ConcurrentHashMap;
027: import java.util.concurrent.ConcurrentMap;
028:
029: import org.apache.mina.common.IoBuffer;
030: import org.apache.mina.common.IoEvent;
031:
032: /**
033: * A default {@link IoEventSizeEstimator} implementation.
034: * <p>
035: * <a href="http://martin.nobilitas.com/java/sizeof.html">Martin's Java Notes</a>
036: * was used for estimation. For unknown types, it inspects declaring fields of the
037: * class of the specified event and the parameter of the event. The size of unknown
038: * declaring fields are approximated to the specified <tt>averageSizePerField</tt>
039: * (default: 64).
040: * <p>
041: * All the estimated sizes of classes are cached for performance improvement.
042: *
043: * @author The Apache MINA Project (dev@mina.apache.org)
044: * @version $Rev: 595517 $, $Date: 2007-11-15 18:31:56 -0700 (Thu, 15 Nov 2007) $
045: */
046: public class DefaultIoEventSizeEstimator implements
047: IoEventSizeEstimator {
048:
049: private final ConcurrentMap<Class<?>, Integer> class2size = new ConcurrentHashMap<Class<?>, Integer>();
050:
051: public DefaultIoEventSizeEstimator() {
052: class2size.put(boolean.class, 4); // Probably an integer.
053: class2size.put(byte.class, 1);
054: class2size.put(char.class, 2);
055: class2size.put(int.class, 4);
056: class2size.put(short.class, 2);
057: class2size.put(long.class, 8);
058: class2size.put(float.class, 4);
059: class2size.put(double.class, 8);
060: class2size.put(void.class, 0);
061: }
062:
063: public int estimateSize(IoEvent event) {
064: return estimateSize((Object) event)
065: + estimateSize(event.getParameter());
066: }
067:
068: public int estimateSize(Object message) {
069: if (message == null) {
070: return 8;
071: }
072:
073: int answer = 8 + estimateSize(message.getClass(), null);
074:
075: if (message instanceof IoBuffer) {
076: answer += ((IoBuffer) message).remaining();
077: } else if (message instanceof CharSequence) {
078: answer += ((CharSequence) message).length() << 1;
079: } else if (message instanceof Iterable) {
080: for (Object m : (Iterable<?>) message) {
081: answer += estimateSize(m);
082: }
083: }
084:
085: return align(answer);
086: }
087:
088: private int estimateSize(Class<?> clazz,
089: Set<Class<?>> visitedClasses) {
090: Integer objectSize = class2size.get(clazz);
091: if (objectSize != null) {
092: return objectSize;
093: }
094:
095: if (visitedClasses != null) {
096: if (visitedClasses.contains(clazz)) {
097: return 0;
098: }
099: } else {
100: visitedClasses = new HashSet<Class<?>>();
101: }
102:
103: visitedClasses.add(clazz);
104:
105: int answer = 8; // Basic overhead.
106: for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
107: Field[] fields = c.getDeclaredFields();
108: for (Field f : fields) {
109: if ((f.getModifiers() & Modifier.STATIC) != 0) {
110: // Ignore static fields.
111: continue;
112: }
113:
114: answer += estimateSize(f.getType(), visitedClasses);
115: }
116: }
117:
118: visitedClasses.remove(clazz);
119:
120: // Some alignment.
121: answer = align(answer);
122:
123: // Put the final answer.
124: class2size.putIfAbsent(clazz, answer);
125: return answer;
126: }
127:
128: private static int align(int size) {
129: if (size % 8 != 0) {
130: size /= 8;
131: size++;
132: size *= 8;
133: }
134: return size;
135: }
136: }
|