package com.francetelecom.rd.stubs.engine; /* * #%L * Matos * $Id:$ * $HeadURL:$ * %% * Copyright (C) 2008 - 2014 Orange SA * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This class maintains table describing the class hierarchy of the handled classes. * It maintains the backward links giving for example the subclass of a class or the * implementors of an interface and provides utility functions to navigate the * hierarchy. * @author Pierre Cregut * */ public class Hierarchy { private Map <Class<?>, List <Class<?>>> implementors = new HashMap <Class<?>, List <Class<?>>> (); private Map <Class<?>, List <Class<?>>> subclasses = new HashMap <Class<?>, List <Class<?>>> (); private List <Class <?>> contents = new ArrayList<Class<?>>(); private Map<Class<?>, Integer> subclassesCount = new HashMap<Class<?>, Integer>(); /** * Add to a one to n map. The n is represented by a list of values. * @param <A> type of the key * @param <B> type of the elements * @param map the map * @param key the key to add * @param value one of the values associated to the key to add. */ public static <A,B> void add(Map <A,List <B>> map,A key, B value) { List <B> list = map.get(key); if (list == null) { list = new ArrayList<B>(); map.put(key, list); } list.add(value); } int countAnnot = 0; int countClass=0; int countItf=0; int countEnum=0; int countPublic = 0; int countProtected = 0; int countPackage = 0; int countPrivate = 0; int countAbstract = 0; /** * Register a new class in the hierarchy tables * @param clazz */ public void register(Class <?> clazz) { statistic(clazz); contents.add(clazz); if (! isVisible(clazz)) return; Class <?> superClass = clazz; do { superClass = superClass.getSuperclass(); } while(superClass != null && !isVisible(superClass)); if (superClass != null) { add(subclasses,superClass, clazz); } for(Class <?> itf : clazz.getInterfaces()) { add(implementors,itf,clazz); } } private boolean isVisible(Class<?> clazz) { int mod = clazz.getModifiers(); return Modifier.isPublic(mod) || Modifier.isProtected(mod); } /** * Register the declared flags of a class for statistics on the modifiers. * @param clazz */ private void statistic(Class <?> clazz) { if (clazz.isAnnotation()) countAnnot++; else if (clazz.isInterface()) countItf++; else if (clazz.isEnum()) countEnum++; else countClass++; int mod = clazz.getModifiers(); if (Modifier.isPublic(mod)) countPublic++; else if (Modifier.isPrivate(mod)) countPrivate++; else if (Modifier.isProtected(mod)) countProtected++; else countPackage ++; if (Modifier.isAbstract(mod)) countAbstract++; } /** * Return classes that are direct sub-classes of the argument. * @param clazz * @return */ public List<Class<?>> getSubclasses(Class<?> clazz) { return subclasses.get(clazz); } /** * All the classes registered in the hierarchy * @return */ public List <Class<?>> getContents() { return contents; } /** * Classes implementing an interface and interface extending a class. * @param clazz * @return */ public List<Class<?>> getImplementors(Class<?> clazz) { return implementors.get(clazz); } /** * Classes implementing an interface and interface extending a class. * @param clazz * @return */ public List<Class<?>> getRecursiveSubclasses(Class<?> clazz) { List <Class <?>> result = new ArrayList <Class<?>>(); List <Class <?>> todo = new ArrayList <Class<?>>(); List <Class <?>> next = new ArrayList <Class <?>>(); result.add(clazz); todo.add(clazz); do { next.clear(); for(Class<?> cl: todo) { List <Class <?>> impl = getSubclasses(cl); if (impl != null) { next.addAll(impl); result.addAll(impl); } } List <Class <?>> aux = todo; todo = next; next = aux; } while (todo.size() > 0); return result; } /** * Take cares of interfaces extended by other to give back the complete list * of classes directly implementing this interface (ie not extending another * class that implements it). * @param clazz * @return */ public List <Class <?>> getExtendedImplementors(Class <?> clazz) { if (clazz.isInterface()) { List <Class <?>> directImplementors = getImplementors(clazz); List <Class <?>> result = new ArrayList <Class<?>>(directImplementors); for(Class <?> implem : directImplementors) { if (implem.isInterface()) result.addAll(getExtendedImplementors(implem)); } return result; } else return getSubclasses(clazz); } /** * Utility method that counts the number of subclasses of a given class and store * the result in a map * @param clazz * @return */ public int count(Class<?> clazz) { Integer c = subclassesCount.get(clazz); if (c != null) return c; int v = 0; List <Class <?>> subList = subclasses.get(clazz); if (subList != null) { for(Class<?> sub : subList) v += 1 + count(sub); } // if (clazz.isInterface() && v==0) // System.err.println("**** " + clazz.getName() + " has no implem ****"); // System.err.println(clazz.getName() + ": " + v); subclassesCount.put(clazz, v); return v; } /** * Utility method providing various statistics on the class. */ public void count() { System.err.println("Annot = " + countAnnot + "/Itf = " + countItf + "/Enum = " + countEnum + "/Class = " + countClass); System.err.println("Public = " + countPublic + "/Private = " + countPrivate + "/Protected = "+ countProtected + "/Package = " + countPackage); System.err.println("Abstract = " + countAbstract + "\n\n"); for (Class<?> c : contents) count(c); } }