/*
* MicroJIAC - A Lightweight Agent Framework
* This file is part of MicroJIAC MIDlet-Maven-Plugin.
*
* Copyright (c) 2007-2012 DAI-Labor, Technische Universität Berlin
*
* This library includes software developed at DAI-Labor, Technische
* Universität Berlin (http://www.dai-labor.de)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/*
* $Id$
*/
package de.jiac.micro.reflect;
import java.beans.IntrospectionException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import de.dailab.jiac.common.aamm.beans.ClassDescriptor;
import de.dailab.jiac.common.aamm.beans.ClassInfo;
import de.dailab.jiac.common.aamm.beans.Introspector;
import de.dailab.jiac.common.aamm.beans.MethodDescriptor;
import de.dailab.jiac.common.aamm.beans.PropertyDescriptor;
import de.jiac.micro.reflect.filter.IFilter;
/**
* @author Marcel Patzlaff
* @version $Revision$
*/
public class ClassInfoReducer {
public final static class ReducedClassInfo extends ClassInfo {
protected final ClassInfo originalInfo;
protected int mask;
private final HashSet<MethodDescriptor> _reducedMethods;
private MethodDescriptor[] _rmds;
private final HashMap<String, PropertyDescriptor> _reducedProperties;
private PropertyDescriptor[] _rpds;
protected ReducedClassInfo(ClassInfo originalInfo, int mask) {
this.originalInfo= originalInfo;
this.mask= mask;
_rpds= null;
_rmds= null;
_reducedProperties= new HashMap<String, PropertyDescriptor>();
PropertyDescriptor[] pds= originalInfo.getPropertyDescriptors();
for(int i= 0; i < pds.length; ++i) {
_reducedProperties.put(pds[i].getName(), pds[i]);
}
_reducedMethods= new HashSet<MethodDescriptor>();
_reducedMethods.addAll(Arrays.asList(originalInfo.getMethodDescriptors()));
}
public ClassDescriptor getClassDescriptor() {
return originalInfo.getClassDescriptor();
}
public MethodDescriptor[] getMethodDescriptors() {
if(_rmds == null) {
_rmds= _reducedMethods.toArray(new MethodDescriptor[_reducedMethods.size()]);
}
return _rmds;
}
public PropertyDescriptor[] getPropertyDescriptors() {
if(_rpds == null) {
_rpds= _reducedProperties.values().toArray(new PropertyDescriptor[_reducedProperties.size()]);
}
return _rpds;
}
public boolean hasWritablePropertiesForMask() {
if(mask == IFilter.IGNORE || (mask & IFilter.PROPERTIES) <= 0) {
return false;
}
PropertyDescriptor[] pds= getPropertyDescriptors();
for(int i= 0; i < pds.length; ++i) {
if(pds[i].isWritable()) {
return true;
}
}
return false;
}
public boolean needsMethodsWithDescriptors() {
return mask != IFilter.IGNORE && (mask & IFilter.METHODS_WITH_DESCRIPTORS) != 0;
}
/*package*/ void reduceWith(ReducedClassInfo sprci) {
// reduce properties
PropertyDescriptor[] pds= sprci.originalInfo.getPropertyDescriptors();
for(int i= 0; i < pds.length; ++i) {
PropertyDescriptor pd= pds[i];
PropertyDescriptor rpd= _reducedProperties.remove(pd.getName());
if(rpd != null) {
_rpds= null;
rpd= PropertyDescriptor.reduce(rpd, pd);
if(rpd != null) {
_reducedProperties.put(pd.getName(), rpd);
}
}
}
// reduce methods
MethodDescriptor[] mds= sprci.originalInfo.getMethodDescriptors();
for(int i= 0; i < mds.length; ++i) {
if(_reducedMethods.remove(mds[i])) {
_rmds= null;
}
}
}
}
private final HashMap<Class<?>, ReducedClassInfo> _classes= new HashMap<Class<?>, ReducedClassInfo>();
private final HashMap<Class<?>, Integer> _masks= new HashMap<Class<?>, Integer>();
private final HashSet<Class<?>> _ignored= new HashSet<Class<?>>();
public void ignoreClass(Class<?> cls) {
_ignored.add(cls);
}
public void insert(Class<?> cls, int mask) {
_masks.put(cls, Integer.valueOf(mask));
}
public void reduceAll() throws IntrospectionException {
for(Map.Entry<Class<?>, Integer> entry : _masks.entrySet()) {
internalReduce(Introspector.getBeanInfo(entry.getKey()), entry.getValue().intValue());
}
}
public ReducedClassInfo[] getSorted() {
ReducedClassInfo[] infos= _classes.values().toArray(new ReducedClassInfo[_classes.size()]);
Arrays.sort(infos);
return infos;
}
private ReducedClassInfo internalReduce(ClassInfo classInfo, int mask) {
Class<?> cls= classInfo.getClassDescriptor().getClazz();
ReducedClassInfo rci= _classes.get(cls);
if(rci == null) {
rci= new ReducedClassInfo(classInfo, mask);
_classes.put(cls, rci);
} else {
rci.mask |= mask;
}
LinkedList<Class<?>> jumpOver= new LinkedList<Class<?>>();
int jumpIndex= 0;
// walk up hierarchy
try {
do {
Class<?> spcls= cls.getSuperclass();
if(spcls != null) {
if(_ignored.contains(spcls)) {
if(!jumpOver.contains(spcls)) {
jumpOver.add(spcls);
}
} else {
ReducedClassInfo sprci= internalReduce(Introspector.getBeanInfo(spcls), rci.mask);
rci.reduceWith(sprci);
}
}
Class<?>[] intfs= cls.getInterfaces();
if(intfs != null) {
for(int i= 0; i < intfs.length; ++i) {
if(_ignored.contains(intfs[i])) {
if(!jumpOver.contains(intfs[i])) {
jumpOver.add(intfs[i]);
}
} else {
ReducedClassInfo intfrci= internalReduce(Introspector.getBeanInfo(intfs[i]), rci.mask);
rci.reduceWith(intfrci);
}
}
}
cls= jumpIndex < jumpOver.size() ? jumpOver.get(jumpIndex++) : null;
} while(cls != null);
} catch (IntrospectionException ie) {
// should not happen here because we only do simple cache lookups
throw new AssertionError(ie);
}
return rci;
}
}