padl.creator.classfile.AbstractClassFileCreator.java Source code

Java tutorial

Introduction

Here is the source code for padl.creator.classfile.AbstractClassFileCreator.java

Source

/*******************************************************************************
 * Copyright (c) 2001-2014 Yann-Gal Guhneuc and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Yann-Gal Guhneuc and others, see in file; API and its implementation
 ******************************************************************************/
package padl.creator.classfile;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarInputStream;
import org.apache.commons.lang.ArrayUtils;
import com.ibm.toad.cfparse.ClassFile;
import com.ibm.toad.cfparse.ConstantPool;
import com.ibm.toad.cfparse.ConstantPoolEntry;
import com.ibm.toad.cfparse.InterfaceList;
import com.ibm.toad.cfparse.MethodInfo;
import com.ibm.toad.cfparse.attributes.AttrInfoList;
import com.ibm.toad.cfparse.attributes.CodeAttrInfo;
import com.ibm.toad.cfparse.instruction.ImmutableCodeSegment;
import com.ibm.toad.cfparse.instruction.JVMConstants;
import com.ibm.toad.cfparse.utils.AttrUtils;
import com.ibm.toad.cfparse.utils.ByteArray;
import padl.creator.classfile.relationship.ContainerRelationshipAnalyzer;
import padl.creator.classfile.relationship.Context;
import padl.creator.classfile.relationship.RelationshipAnalyzer;
import padl.creator.classfile.util.ExtendedFieldInfo;
import padl.creator.classfile.util.ExtendedMethodInfo;
import padl.creator.classfile.util.PackageCreator;
import padl.creator.classfile.util.Utils;
import padl.event.AnalysisEvent;
import padl.event.IModelListener;
import padl.kernel.Constants;
import padl.kernel.IClass;
import padl.kernel.ICodeLevelModel;
import padl.kernel.IConstituentOfEntity;
import padl.kernel.IConstructor;
import padl.kernel.IContainerAggregation;
import padl.kernel.IDelegatingMethod;
import padl.kernel.IField;
import padl.kernel.IFirstClassEntity;
import padl.kernel.IGhost;
import padl.kernel.IInterfaceActor;
import padl.kernel.IMethod;
import padl.kernel.IPackage;
import padl.kernel.IParameter;
import padl.kernel.impl.ConstituentsRepository;
import padl.kernel.impl.Factory;
import padl.util.Util;
import util.io.ProxyConsole;
import util.io.SubtypeLoader;

/**
 * @author Yann-Gal Guhneuc
 */
abstract class AbstractClassFileCreator {
    private static String[] computeMethodCallees(final ConstantPool aConstantPool,
            final ExtendedMethodInfo aMethodInfo) {

        final AttrInfoList attributeInfoList = aMethodInfo.getAttributes();
        final CodeAttrInfo codeAttributeInfo = (CodeAttrInfo) attributeInfoList.get("Code");
        final List calles = new ArrayList();

        if (codeAttributeInfo != null) {
            final byte[] rawCode = codeAttributeInfo.getCode();
            final ImmutableCodeSegment immutableCodeSegment = new ImmutableCodeSegment(rawCode);
            final int numberOfInstructions = immutableCodeSegment.getNumInstructions();

            for (int j = 0; j < numberOfInstructions; j++) {
                final int offset = immutableCodeSegment.getOffset(j);
                final int opCode = ByteArray.getByteAtOffset(rawCode, offset);

                switch (opCode) {
                case JVMConstants.INVOKEINTERFACE:
                case JVMConstants.INVOKESPECIAL:
                case JVMConstants.INVOKESTATIC:
                case JVMConstants.INVOKEVIRTUAL: {
                    int num = ByteArray.getShortAtOffset(rawCode, offset + 1);
                    ConstantPoolEntry constantPoolEntry = aConstantPool.get(num);
                    int[] indices = constantPoolEntry.getIndices();
                    // TODO: This test should not exist and is there only because of the CFParseBCELConvertor
                    if (indices != null) {
                        String className = aConstantPool.getAsJava(indices[0]);
                        String nameAndType = aConstantPool.getAsJava(indices[1]);
                        calles.add(className + '.' + nameAndType.substring(0, nameAndType.indexOf('.')));
                    }
                }
                    break;
                default:
                    break;
                }
            }
        }

        final String[] arrayOfCallees = new String[calles.size()];
        calles.toArray(arrayOfCallees);
        return arrayOfCallees;
    }

    private final ConstituentsRepository constituentsRepository;
    private final List listOfClassFiles;
    private final Map mapOfIDsEntities;
    private final Map mapOfPackageNamesPackages;
    private final boolean storeMethodInvocation;

    public AbstractClassFileCreator(final String[] someClassFiles, final boolean recurseIntoDirectories,
            final boolean storeMethodInvocation) {

        this.constituentsRepository = ConstituentsRepository.getInstance();
        this.listOfClassFiles = new ArrayList();
        this.mapOfIDsEntities = new HashMap();
        this.mapOfPackageNamesPackages = new HashMap();
        this.storeMethodInvocation = storeMethodInvocation;

        for (int i = 0; i < someClassFiles.length; i++) {
            // I add this new package to the current AbstractLevelModel model.
            ProxyConsole.getInstance().normalOutput().print("Loading class files in: ");
            ProxyConsole.getInstance().normalOutput().println(someClassFiles[i]);

            final ClassFile[] classFiles;
            if (someClassFiles[i].endsWith(".jar")) {
                classFiles = SubtypeLoader.loadSubtypesFromJar(null, someClassFiles[i], ".class");
            } else if (someClassFiles[i].endsWith(".class")) {
                classFiles = SubtypeLoader.loadSubtypeFromFile(null, someClassFiles[i], ".class");
            } else if (recurseIntoDirectories) {
                // Yann 2004/10/16: Recursion!
                // I add a new flag to know whether or not to recurse
                // into directories when loading class files. I should
                // change this to get as parameter a new type Directory 
                // that would contain the name of a directory and whether
                // to recurse for this paricular directory.
                // TODO: Replace the recurseIntoDirectories with a type Directory
                classFiles = SubtypeLoader.loadRecursivelySubtypesFromDir(null, someClassFiles[i], ".class");
            } else {
                classFiles = SubtypeLoader.loadSubtypesFromDir(null, someClassFiles[i], ".class");
            }

            // @Note David: Is this sorting of classes by the alphabetical order?
            // If it is, why is 
            // Arrays.sort(results, new ClassNameAlphabeticalComparator()); 
            // in SubtypeLoader.loadSubtypesFromJar?

            for (int j = 0; j < classFiles.length; j++) {
                // Yann 2005/09/26: Member classes!
                // I now handle membre classes, thus, I need class files
                // to be sorted by the alphabetical order of their names.
                final String currentClassFileName = classFiles[j].getName();
                final int numberOfClassFiles = this.listOfClassFiles.size();
                int index = 0;
                while (index < numberOfClassFiles && ((ClassFile) this.listOfClassFiles.get(index)).getName()
                        .compareTo(currentClassFileName) <= 0) {

                    index++;
                }
                this.listOfClassFiles.add(index, classFiles[j]);
            }
        }
    }

    public AbstractClassFileCreator(final JarInputStream inputStream, final boolean storeMethodInvocation) {

        this.constituentsRepository = ConstituentsRepository.getInstance();
        this.listOfClassFiles = new ArrayList();
        this.mapOfIDsEntities = new HashMap();
        this.mapOfPackageNamesPackages = new HashMap();
        this.storeMethodInvocation = storeMethodInvocation;

        final ClassFile[] classFiles;
        // I add this new package to the current AbstractLevelModel model.
        ProxyConsole.getInstance().normalOutput().print("Loading class files from in: ");
        ProxyConsole.getInstance().normalOutput().println("jar input stream");

        classFiles = SubtypeLoader.loadSubtypesFromJarInputStream(null, inputStream, ".class");

        // @Note David: Is this sorting of classes by the alphabetical order?
        // If it is, why is 
        // Arrays.sort(results, new ClassNameAlphabeticalComparator()); 
        // in SubtypeLoader.loadSubtypesFromJar?

        for (int j = 0; j < classFiles.length; j++) {
            // Yann 2005/09/26: Member classes!
            // I now handle membre classes, thus, I need class files
            // to be sorted by the alphabetical order of their names.
            final String currentClassFileName = classFiles[j].getName();
            final int numberOfClassFiles = this.listOfClassFiles.size();
            int index = 0;
            while (index < numberOfClassFiles && ((ClassFile) this.listOfClassFiles.get(index)).getName()
                    .compareTo(currentClassFileName) <= 0) {

                index++;
            }
            this.listOfClassFiles.add(index, classFiles[j]);
        }
    }

    public void create(final ICodeLevelModel aCodeLevelModel) {
        final ClassFile[] listOfEntities = this.constituentsRepository.getEntities();
        final ClassFile[] listOfElements = this.constituentsRepository.getElements();

        this.createPackages(aCodeLevelModel, this.listOfClassFiles, this.constituentsRepository, listOfEntities);

        this.createEntities(aCodeLevelModel, this.listOfClassFiles, this.constituentsRepository, listOfEntities);

        this.createElements(aCodeLevelModel, this.listOfClassFiles, this.constituentsRepository, listOfElements);
    }

    private void createElements(final ICodeLevelModel aCodeLevelModel, final List listOfSourceConstituents,
            final ConstituentsRepository constituentsRepository, final ClassFile[] listOfElements) {

        RelationshipAnalyzer.initialise(this.mapOfIDsEntities);
        Context.initialise(this.mapOfIDsEntities);

        int[] sortedElements = new int[listOfElements.length];
        final StringBuffer buffer = new StringBuffer();
        String constituentName;

        for (int x = 0; x < listOfElements.length; x++) {
            constituentName = constituentsRepository.getElements()[x].getName();

            try {
                buffer.append("recognize");
                buffer.append(constituentName.substring(constituentName.lastIndexOf('.') + 1));
                buffer.append("Priority");
                sortedElements[x] = ((Integer) this.getClass().getMethod(buffer.toString(), new java.lang.Class[0])
                        .invoke(this, new Object[0])).intValue();
                buffer.setLength(0);
            } catch (final Throwable t) {
                t.printStackTrace(ProxyConsole.getInstance().errorOutput());
            } finally {
                // Yann 2004/03/31: Reset!
                // In any case (okay or exception), I reset
                // the buffer from its content.
                buffer.setLength(0);
            }
        }
        sortedElements = Utils.sortByPriority(sortedElements);

        // Yann 2002/08/01: Concurrent modification.
        // While I iterate over the list of entities,
        // I may want to add new entities (instances of Ghost),
        // thus I cannot use the iterator mechanism provided
        // by Java, because it implements a fail-safe security.
        // Yann 2004/04/10: Sorting out!
        // The fix described in the above comment is no longer valid.
        // I now sort the entities and the elements to get them in a
        // consistent order across platforms and implementations
        // (mainly for testing purposes). Thus, ghosts created during
        // the creation of elements may "push down" the list the entity
        // being analyzed... and element will be added (or tried to)
        // more than once, resulting in not-good-looking exceptions.
        // I added code to refocus the i index.

        // Yann 2006/02/10: Wrong order... all this time!
        // I should not iterate over entities and call the
        // recognise() methods on it but iterate over each
        // recognise() methods and call each on all the entities
        // this should prevent the "duplicate actor ID" problem...

        final List listOfSubmittedElements = new ArrayList();
        for (int elementRecogniserNumber = 0; elementRecogniserNumber < listOfElements.length; elementRecogniserNumber++) {

            // Yann 2006/08/03: Member entities!
            // I should not iterate over the entities of the code-level model
            // because this model does not contain *directly* references to
            // member entities and thus these entities are not fed with their
            // methods and fields!!!
            //   final Iterator iteratorOnEntities =
            //      aCodeLevelModel.getIteratorOnConstituents(IEntity.class);
            // I now iterate over the list of provided classfiles, thus
            // including method in member classes.
            final Iterator iteratorOnEntities = listOfSourceConstituents.iterator();
            while (iteratorOnEntities.hasNext()) {
                // I look for the entity corresponding instance of class Class.
                // I cannot use:
                //      Class.forName(((Entity) enum.nextElement()).getName())
                // Since the given user's classes may not be in the classpath and
                // have been loaded from a different class loader.
                // Yann 2005/10/07: Packages!
                // A model may now contrain entities and packages.
                final ClassFile currentClass = (ClassFile) iteratorOnEntities.next();
                final char[] currentClassName = currentClass.getName().toCharArray();

                if (!Utils.isAnonymousOrLocalEntity(currentClassName)
                        && !Utils.isLocalOrLocalMemberEntity(currentClassName)) {

                    final IFirstClassEntity firstClassEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel,
                            currentClassName, this.mapOfIDsEntities);

                    constituentName = constituentsRepository.getElements()[sortedElements[elementRecogniserNumber]]
                            .getName();

                    if (!(firstClassEntity instanceof IGhost)) {
                        aCodeLevelModel.fireModelChange(IModelListener.ENTITY_ANALYZED,
                                new AnalysisEvent(currentClassName, constituentName.toCharArray()));

                        // I reset the list of submitted elements and entities.
                        listOfSubmittedElements.clear();

                        // I fill up the Element.
                        for (int i = 0; i < currentClass.getMethods().length(); i++) {

                            // Yann 2016/09/21: Synthetic attributes!
                            // Starting with JDK 1.6. generic introduced
                            // all kind of perks... including "new"
                            // synthetic methods!
                            // https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html
                            final MethodInfo methodInfo = currentClass.getMethods().get(i);
                            if (AttrUtils.getAttrByName(methodInfo.getAttrs(), "Synthetic") == null) {

                                listOfSubmittedElements.add(new ExtendedMethodInfo(currentClass, methodInfo));
                            }
                        }

                        for (int i = 0; i < currentClass.getFields().length(); i++) {

                            listOfSubmittedElements
                                    .add(new ExtendedFieldInfo(currentClass, currentClass.getFields().get(i)));
                        }

                        try {
                            // Yann 2002/07/31: Priorities.
                            // I must keep the fields and the methods in
                            // the list of submitted constituents,
                            // because they might be used later to create
                            // a Aggregation linked with them.
                            // Yann 2003/12/22: ICodeLevelModelCreator.
                            // I now use the method provided by the instance
                            // of ICodeLevelModelCreator.
                            //   Misc
                            //      .getDeclaredMethod(
                            //         constituentRepository
                            //            .getElements()[sortedElements[x]],
                            //         "recognize")
                            //      .invoke(
                            //         null,
                            //         new Object[] {
                            //            listOfSubmittedElements,
                            //            this });
                            buffer.append("recognize");
                            buffer.append(constituentName.substring(constituentName.lastIndexOf('.') + 1));

                            this.getClass()
                                    .getMethod(buffer.toString(),
                                            new java.lang.Class[] { List.class, ICodeLevelModel.class })
                                    .invoke(this, new Object[] { listOfSubmittedElements, aCodeLevelModel });
                        } catch (final NoSuchMethodException t) {
                            ProxyConsole.getInstance().errorOutput()
                                    .print(AbstractClassFileCreator.class.getName());
                            ProxyConsole.getInstance().errorOutput().print(" cannot invoke ");
                            ProxyConsole.getInstance().errorOutput()
                                    .println(listOfElements[sortedElements[elementRecogniserNumber]].getName());
                            //   t.printStackTrace(ProxyConsole
                            //      .getInstance()
                            //      .errorOutput());
                            // Yann 2004/06/02: Flush.
                            // I make sure I flush the output stream to
                            // display as soon as possible exceptions.
                            // Yann 2004/07/15: Flush!
                            // This is now taken care of by the OutputManager class.
                            //   OutputManager
                            //      .getCurrentOutputManager()
                            //      .getErrorOutput()
                            //      .flush();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace(ProxyConsole.getInstance().errorOutput());
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace(ProxyConsole.getInstance().errorOutput());
                        } catch (InvocationTargetException e) {
                            e.printStackTrace(ProxyConsole.getInstance().errorOutput());
                        } catch (SecurityException e) {
                            e.printStackTrace(ProxyConsole.getInstance().errorOutput());
                        } finally {
                            // Yann 2004/03/31: Reset!
                            // In any case (okay or exception), I reset
                            // the buffer from its content.
                            buffer.setLength(0);
                        }
                    } else {
                        aCodeLevelModel.fireModelChange(IModelListener.ENTITY_SKIPPED,
                                new AnalysisEvent(currentClassName, constituentName.toCharArray()));
                    }
                }
            }

            // Yann 2004/04/10: Refocus.
            // Ghosts created during the analysis may have
            // "pushed down" the current entities down the
            // temporary list. I need to refocus the index
            // accordingly. I start from the index because
            // entities can be added only, not deleted.
            // I need to do this for each entity.
            //   for (int j = i; j < temporayListOfEntities.size(); j++) {
            //      if (((IEntity) temporayListOfEntities.get(j))
            //         .getName()
            //         .equals(currentClassName)) {
            //
            //         i = j;
            //         j = temporayListOfEntities.size();
            //      }
            //   }
        }
    }

    private void createEntities(final ICodeLevelModel aCodeLevelModel, final List listOfSourceConstituents,
            final ConstituentsRepository constituentsRepository, final ClassFile[] listOfEntities) {

        // Yann 2006/02/03: Spring cleaning.
        // Handling member classes makes it harder and harder to
        // analyse entities using the legacy code below. I rewrite
        // this algorithm to perform the creation of entities
        // (including membre entitie) and their connection
        // (inheritance and implementation) in two pass:
        // 1. I create all the entities, including member entities.
        //    I put the entities in the right packages.
        // 2. I connect the entities with one another through
        //    inheritance and implementation, as appropriate.

        // 1.
        Iterator iterator = listOfSourceConstituents.iterator();
        while (iterator.hasNext()) {
            final ClassFile classFile = (ClassFile) iterator.next();
            final String entityDisplayID = classFile.getName();
            char[] entityID = entityDisplayID.toCharArray();

            // I assume that the classfiles are sorted such as member
            // entities appear *after* their containing entities.

            // Yann 2011/10/01: Local entity!
            // There is an entity with ID: 
            //   javax.swing.JSlider$1$SmartHashtable$LabelUIResource
            // that must be dealt with as a local entity.
            if (!Utils.isAnonymousOrLocalEntity(entityID) && !Utils.isLocalOrLocalMemberEntity(entityID)) {
                if (!Utils.isMemberEntity(entityID)) {
                    final IFirstClassEntity firstClassEntity;
                    if (Utils.isClass(classFile)) {
                        firstClassEntity = aCodeLevelModel.getFactory().createClass(entityID,
                                Utils.computeSimpleName(entityID));
                    } else {
                        firstClassEntity = aCodeLevelModel.getFactory().createInterface(entityID,
                                Utils.computeSimpleName(entityID));
                    }
                    firstClassEntity.setVisibility(classFile.getAccess());

                    final IPackage enclosingPackage = Utils.getPackage(this.mapOfPackageNamesPackages, entityID);
                    enclosingPackage.addConstituent(firstClassEntity);
                    this.mapOfIDsEntities.put(entityDisplayID, firstClassEntity);
                } else {
                    final IFirstClassEntity memberEntity;
                    if (Utils.isClass(classFile)) {
                        memberEntity = aCodeLevelModel.getFactory().createMemberClass(entityID,
                                Utils.computeSimpleName(entityID));
                    } else {
                        memberEntity = aCodeLevelModel.getFactory().createMemberInterface(entityID,
                                Utils.computeSimpleName(entityID));
                    }
                    memberEntity.setVisibility(classFile.getAccess());

                    final char[] enclosingEntityID = ArrayUtils.subarray(entityID, 0,
                            ArrayUtils.lastIndexOf(entityID, '$'));
                    Utils.searchForEntity(aCodeLevelModel, enclosingEntityID)
                            .addConstituent((IConstituentOfEntity) memberEntity);
                    this.mapOfIDsEntities.put(entityDisplayID, memberEntity);
                }
            }
        }

        // 2. At this point, all missing entities must be ghosts!
        iterator = listOfSourceConstituents.iterator();
        while (iterator.hasNext()) {
            final ClassFile classFile = (ClassFile) iterator.next();
            final String entityDisplayName = classFile.getName();
            final char[] entityName = entityDisplayName.toCharArray();

            if (!Utils.isAnonymousOrLocalEntity(entityName) && !Utils.isLocalOrLocalMemberEntity(entityName)) {

                // Yann 2008/11/06: Performance.
                // To increase the performance when building a model
                // from Java code, I maintain internally a map of
                // IDs and entities.
                final IFirstClassEntity firstClassEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel, entityName,
                        this.mapOfIDsEntities);

                // Yann 2006/02/09: java.lang.Object
                // The java.lang.Object class does not have a superclass.
                // Hence, its superclass name would be "" but I don't
                // want to create a Ghost with no name...
                // Yann 2014/04/11: Object!
                // Wow, for the longest time, I was not adding Object 
                // as super-entity for interfaces: weird that it never 
                // caused problem before???
                if (!(firstClassEntity.equals(Factory.getInstance().createHierarchyRoot()))) {

                    final String superClassDisplayName = classFile.getSuperName();
                    final char[] superClassName = superClassDisplayName.toCharArray();
                    final IFirstClassEntity superEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel,
                            superClassName, this.mapOfIDsEntities);
                    ((IFirstClassEntity) firstClassEntity).addInheritedEntity(superEntity);
                }

                final InterfaceList interfaceList = classFile.getInterfaces();
                for (int i = 0; i < interfaceList.length(); i++) {
                    final String superInterfaceDisplayName = interfaceList.get(i);
                    final char[] superInterfaceName = superInterfaceDisplayName.toCharArray();
                    final IFirstClassEntity superEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel,
                            superInterfaceName, this.mapOfIDsEntities);

                    if (firstClassEntity instanceof IClass) {
                        ((IClass) firstClassEntity).addImplementedInterface((IInterfaceActor) superEntity);
                    } else {
                        ((IInterfaceActor) firstClassEntity).addInheritedEntity(superEntity);
                    }
                }
            }
        }
    }

    private void createPackages(final ICodeLevelModel aCodeLevelModel, final List listOfSourceConstituents,
            final ConstituentsRepository constituentsRepository, final ClassFile[] listOfEntities) {

        // Yann 2008/11/03: Packages.
        // Packages are now mandatory!

        final Iterator iterator = listOfSourceConstituents.iterator();
        while (iterator.hasNext()) {
            final ClassFile classFile = (ClassFile) iterator.next();
            final String entityDisplayName = classFile.getName();
            final char[] entityName = entityDisplayName.toCharArray();
            final char[] packageName = Utils.extractPackageName(entityName);
            final IPackage enclosingPackage = Utils.searchForPackage(aCodeLevelModel, entityName,
                    new PackageCreator() {
                        public IPackage create(final char[] aName) {
                            return Factory.getInstance().createPackage(aName);
                        }
                    });
            if (!this.mapOfPackageNamesPackages.containsKey(packageName)) {
                this.mapOfPackageNamesPackages.put(String.valueOf(packageName), enclosingPackage);
            }
        }
    }

    public List recognizeAggregation(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeAggregationPriority() {
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeAssociation(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeAssociationPriority() {
        return Constants.HIGH_RECOGNITION_PRIORITY;
    }

    public List recognizeComposition(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeCompositionPriority() {
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeConstructor(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        final List notRecognized = new ArrayList();
        final Iterator iterator = aListOfSubmittedConstituents.iterator();

        while (iterator.hasNext()) {
            final Object element = iterator.next();
            if (element instanceof ExtendedMethodInfo) {
                ExtendedMethodInfo currentExtendedMethod = (ExtendedMethodInfo) element;
                // Yann 2004/03/28: Constructors.
                // If the method is a constructor, I take care
                // of giving it the proper name and return type.
                final char[] name = currentExtendedMethod.getName();

                // Yann 2005/08/15: Inner classes!
                // I now manage inner and anonymous classes...
                //   if (Utils.isSpecialMethod(name)
                //      && !Misc.isAnonymousClass(
                //         currentExtendedMethod.getDeclaringClassName())) {
                if (Utils.isSpecialMethod(name)) {
                    final IConstructor currentConstructor = aCodeLevelModel.getFactory().createConstructor(
                            Utils.computeSignature(currentExtendedMethod),
                            Util.computeSimpleName(currentExtendedMethod.getDeclaringClassName()));

                    currentConstructor.setVisibility(currentExtendedMethod.getVisibility());

                    final char[][] detectedParameters = currentExtendedMethod.getParameters();
                    for (int i = 0; i < detectedParameters.length; i++) {
                        // Yann 2004/01/25: Arrays and primitive types!
                        // I must be careful with arrays (remove the
                        // brackets) and primitive types (do not attempt
                        // to create a Ghost from them).
                        // Yann 2009/05/02: No String anymore!
                        // Cool, eh?
                        char[] paramType = detectedParameters[i];
                        int cardinality = 1;
                        final int bracketIndex = ArrayUtils.indexOf(paramType, '[');
                        if (bracketIndex > -1) {
                            cardinality = (paramType.length - bracketIndex) / 2 + 1;
                            paramType = ArrayUtils.subarray(paramType, 0, bracketIndex);
                        }

                        final IParameter parameter = this.createParameter(aCodeLevelModel, paramType, cardinality);
                        currentConstructor.addConstituent(parameter);
                    }

                    // Yann 2005/12/29: Duplicate...
                    // Actually, the RelationshipAnalyser might already have created
                    // a method in an entity if this method was called from another
                    // entity. Thus, there would be an attempt to add a "duplicate"
                    // element, which is legitimate but taken care of by the new condition.
                    final IFirstClassEntity firstClassEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel,
                            currentExtendedMethod.getDeclaringClassName(), this.mapOfIDsEntities);
                    if (!firstClassEntity.doesContainConstituentWithID(currentConstructor.getID())) {

                        firstClassEntity.addConstituent(currentConstructor);
                    }
                }
            } else {
                notRecognized.add(element);
                // This is not a method, next...
            }
        }

        return notRecognized;
    }

    private IParameter createParameter(final ICodeLevelModel aCodeLevelModel, final char[] someParamType,
            final int cardinality) {

        final IParameter parameter;
        if (Util.isPrimtiveType(someParamType)) {
            parameter = aCodeLevelModel.getFactory().createParameter(
                    aCodeLevelModel.getFactory().createPrimitiveEntity(someParamType), cardinality);
        } else {
            parameter = aCodeLevelModel.getFactory().createParameter(
                    Utils.getEntityOrCreateGhost(aCodeLevelModel, someParamType, this.mapOfIDsEntities),
                    cardinality);
        }
        return parameter;
    }

    public int recognizeConstructorPriority() {
        // Yann 2004/01/25: Priority.
        // Priority should be:
        //    return Constants.LOWEST_RECOGNITION_PRIORITY;
        // Yann 2004/08/09: Priority.
        // Priorities as they are now make more sense.
        return Constants.HIGH_RECOGNITION_PRIORITY;
    }

    public List recognizeContainerAggregation(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        // Yann 2007/10/30: AACRelationshipAnalyser!
        // The building of the relationships is now
        // externalised in a real analysis.
        if (Utils.ENABLE_BUILT_IN_AAC_ANALYSIS) {
            ContainerRelationshipAnalyzer.recognizeContainerAggregation(aListOfSubmittedConstituents,
                    aCodeLevelModel);
        }

        return aListOfSubmittedConstituents;
    }

    public int recognizeContainerAggregationPriority() {
        // Yann 2004/01/25: Priority.
        // Priority should be:
        //    return Constants.LOW_RECOGNITION_PRIORITY;
        // Yann 2004/08/09: Priority.
        // Priorities as they are now make more sense.
        return Constants.LOW_RECOGNITION_PRIORITY;
    }

    public List recognizeContainerComposition(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeContainerCompositionPriority() {
        // Yann 2004/01/25: Priority.
        // Priority should be:
        //    return Constants.LOW_RECOGNITION_PRIORITY;
        // Yann 2004/08/09: Priority.
        // Priorities as they are now make more sense.
        return Constants.LOW_RECOGNITION_PRIORITY;
    }

    public List recognizeCreation(final List aListOfSubmittedConstituents, final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeCreationPriority() {
        return Constants.LOW_RECOGNITION_PRIORITY;
    }

    public List recognizeDelegatingMethod(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        // A method submitted is a PDelegating method if inside the
        // the method body there is one method call to a method that
        // has the same name.
        final Iterator iterator = aListOfSubmittedConstituents.iterator();
        while (iterator.hasNext()) {
            final Object member = iterator.next();

            if (member instanceof ExtendedMethodInfo) {
                final ExtendedMethodInfo extendedMethodInfo = (ExtendedMethodInfo) member;
                // final MethodInfo methodInfo = extendedMethodInfo.getMethod();

                final String[] callees = AbstractClassFileCreator.computeMethodCallees(
                        extendedMethodInfo.getDeclaringClassConstantPool(), extendedMethodInfo);

                if (callees.length == 1) {
                    if (callees[0].substring(callees[0].lastIndexOf('.') + 1)
                            .equals(extendedMethodInfo.getName())) {

                        final String calleesTypeName = callees[0].substring(0, callees[0].lastIndexOf('.'));

                        final IFirstClassEntity currentEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel,
                                extendedMethodInfo.getDeclaringClassName(), this.mapOfIDsEntities);

                        final Iterator iteratorOnContainerAggregation = currentEntity
                                .getIteratorOnConstituents(IContainerAggregation.class);
                        while (iteratorOnContainerAggregation.hasNext()) {
                            final IContainerAggregation aggregation = (IContainerAggregation) iteratorOnContainerAggregation
                                    .next();

                            // Yann 2003/12/15: FieldType vs. TargetEntity
                            // In previous version, the if was about
                            // getFieldType() (see v1) in the stead of
                            // getTargetEntity(). Now, it is the target
                            // actor that we want to check.
                            if (aggregation.getTargetEntity().equals(calleesTypeName)) {

                                // TODO: The target method should not be "null"! 
                                final IDelegatingMethod delegatingMethod = aCodeLevelModel.getFactory()
                                        .createDelegatingMethod(extendedMethodInfo.getName(), aggregation, null);
                                currentEntity.addConstituent(delegatingMethod);
                                iterator.remove();
                            }
                        }
                    }
                }
            }
        }

        return aListOfSubmittedConstituents;
    }

    public int recognizeDelegatingMethodPriority() {
        return Constants.LOWEST_RECOGNITION_PRIORITY;
    }

    public List recognizeEnum(final List aListOfSubmittedConstituents, final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeEnumPriority() {
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeField(final List aListOfSubmittedConstituents, final ICodeLevelModel aCodeLevelModel) {

        final List notRecognized = new ArrayList();
        final Iterator enumarator = aListOfSubmittedConstituents.iterator();
        while (enumarator.hasNext()) {
            final Object element = enumarator.next();
            if (element instanceof ExtendedFieldInfo) {
                final ExtendedFieldInfo currentField = (ExtendedFieldInfo) element;
                char[] fieldType = currentField.getType();
                final int cardinality = Util.isArrayOrCollection(fieldType) ? Constants.CARDINALITY_MANY
                        : Constants.CARDINALITY_ONE;

                // Yann 2003/11/29: Array!
                // I must take care of removing brackets for array.
                int index;
                if ((index = ArrayUtils.indexOf(fieldType, '[')) == -1) {
                    index = fieldType.length;
                }
                fieldType = ArrayUtils.subarray(fieldType, 0, index);

                // Yann 2002/08/01: Ghost!
                // From now on, if an entity cannot be found in the
                // list of entities, I create a ghost for it...
                // Yann 2003/11/29: Primitive type.
                // I must take care not to add primitive type.
                final IField field;
                if (Util.isPrimtiveType(fieldType)) {
                    field = aCodeLevelModel.getFactory().createField(currentField.getName(), currentField.getName(),
                            fieldType, cardinality);
                } else {
                    final IFirstClassEntity targetEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel, fieldType,
                            this.mapOfIDsEntities);
                    // Yann 2006/02/08: Members!
                    // The getConstituentFromID() method takes care of members and ghosts...
                    //   if (targetEntity == null
                    //      && !Utils.isAnonymousEntity(fieldType)) {
                    //
                    //      targetEntity =
                    //         aCodeLevelModel.getFactory().createGhost(
                    //            fieldType);
                    //      aCodeLevelModel.addConstituent(targetEntity);
                    //   }
                    field = aCodeLevelModel.getFactory().createField(currentField.getName(), currentField.getName(),
                            targetEntity.getID(), cardinality);
                }
                field.setVisibility(currentField.getVisibility());

                final IFirstClassEntity firstClassEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel,
                        currentField.getDeclaringClassName(), this.mapOfIDsEntities);
                firstClassEntity.addConstituent(field);
            } else {
                // this is not a field, next ...
                notRecognized.add(element);
            }
        }

        return notRecognized;
    }

    public int recognizeFieldPriority() {
        // Yann 2004/01/25: Priority.
        // Priority should be:
        //    return Constants.LOWEST_RECOGNITION_PRIORITY;
        // Yann 2004/08/09: Priority.
        // Priorities as they are now make more sense.
        return Constants.HIGHEST_RECOGNITION_PRIORITY;
    }

    public List recognizeGeneralisation(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeGeneralisationPriority() {
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeImplementation(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeImplementationPriority() {
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeMethod(final List aListOfSubmittedConstituents, final ICodeLevelModel aCodeLevelModel) {

        final List notRecognized = new ArrayList();
        final Iterator iterator = aListOfSubmittedConstituents.iterator();

        while (iterator.hasNext()) {
            final Object element = iterator.next();
            if (element instanceof ExtendedMethodInfo) {
                ExtendedMethodInfo currentExtendedMethod = (ExtendedMethodInfo) element;
                // Yann 2004/03/28: Constructors.
                // If the method is a constructor, I take care
                // of giving it the proper name and return type.
                final char[] name = currentExtendedMethod.getName();
                if (!Utils.isSpecialMethod(name)) {
                    final IMethod currentMethod = aCodeLevelModel.getFactory()
                            .createMethod(Utils.computeSignature(currentExtendedMethod), name);

                    // Farouk 2004/02/19: Constituent ID.
                    // The method makeSignature is the new way to give an
                    // actor ID to a method, instead of using toString()
                    // from MethodInfo.

                    currentMethod.setReturnType(currentExtendedMethod.getReturnType());

                    currentMethod.setVisibility(currentExtendedMethod.getVisibility());

                    final char[][] detectedParameters = currentExtendedMethod.getParameters();
                    for (int i = 0; i < detectedParameters.length; i++) {
                        // Yann 2004/01/25: Arrays and primitive types!
                        // I must be careful with arrays (remove the
                        // brackets) and primitive types (do not attempt
                        // to create a Ghost from them).
                        // Yann 2006/02/08: Members!
                        // The searchForEntity() method takes care of members and ghosts...
                        //   if (anEntity == null
                        //      && !padl.util.Util.isPrimtiveType(paramType)
                        //      && !Utils.isAnonymousEntity(paramType)) {
                        //
                        //      anEntity =
                        //         aCodeLevelModel.getFactory().createGhost(
                        //            paramType);
                        //      aCodeLevelModel.addConstituent(anEntity);
                        //   }
                        //
                        // Yann 2004/08/07: Parameters!
                        // Parameters now take care of their
                        // cardinlity by themselves...
                        // Yann 2007/08/31: Member...
                        // I should not replace the $ sign by
                        // a . because then I cannot know that
                        // the type is a member type anymore...
                        // this would not happen if IEntity
                        // was used instead of String!
                        //
                        // Yann 2009/05/02: No String anymore!
                        // Cool, eh?
                        char[] paramType = detectedParameters[i];
                        int cardinality = 1;
                        final int bracketIndex = ArrayUtils.indexOf(paramType, '[');
                        if (bracketIndex > -1) {
                            cardinality = (paramType.length - bracketIndex) / 2 + 1;
                            paramType = ArrayUtils.subarray(paramType, 0, bracketIndex);
                        }

                        final IParameter parameter = this.createParameter(aCodeLevelModel, paramType, cardinality);
                        currentMethod.addConstituent(parameter);
                    }

                    // Yann 2005/12/29: Duplicate...
                    // Actually, the RelationshipAnalyser might already have created
                    // a method in an entity if this method was called from another
                    // entity. Thus, there would be an attempt to add a "duplicate"
                    // element, which is legitimate but taken care of by the new condition.
                    final IFirstClassEntity firstClassEntity = Utils.getEntityOrCreateGhost(aCodeLevelModel,
                            currentExtendedMethod.getDeclaringClassName(), this.mapOfIDsEntities);
                    if (!firstClassEntity.doesContainConstituentWithID(currentMethod.getID())) {

                        firstClassEntity.addConstituent(currentMethod);
                    }
                }
            } else {
                notRecognized.add(element);
                // This is not a method, next...
            }
        }

        return notRecognized;
    }

    public int recognizeMethodPriority() {
        // Yann 2004/01/25: Priority.
        // Priority should be:
        //    return Constants.LOWEST_RECOGNITION_PRIORITY;
        // Yann 2004/08/09: Priority.
        // Priorities as they are now make more sense.
        return Constants.HIGH_RECOGNITION_PRIORITY;
    }

    public List recognizeRelationship(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        // Yann 2007/10/30: Do not remove!
        // Even though I clearly distinguish now between
        // code-level models and idiom-level models, I
        // keep this call to make sure that MethodInvocation
        // are properly created because I need them for the
        // AACRelationshipAnalyser
        RelationshipAnalyzer.recogniseRelationship(aListOfSubmittedConstituents, aCodeLevelModel,
                this.storeMethodInvocation);

        return aListOfSubmittedConstituents;
    }

    public int recognizeRelationshipPriority() {
        // Yann 2004/01/25: Priority.
        // Priority should be:
        //    return Constants.HIGHEST_RECOGNITION_PRIORITY;
        // Yann 2004/08/09: Priority.
        // Priorities as they are now make more sense.
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeSpecialisation(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeSpecialisationPriority() {
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeStructure(final List aListOfSubmittedConstituents, final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeStructurePriority() {
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeUnion(final List aListOfSubmittedConstituents, final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeUnionPriority() {
        return Constants.NORMAL_RECOGNITION_PRIORITY;
    }

    public List recognizeUseRelationship(final List aListOfSubmittedConstituents,
            final ICodeLevelModel aCodeLevelModel) {

        return aListOfSubmittedConstituents;
    }

    public int recognizeUseRelationshipPriority() {
        // Yann 2004/01/25: Priority.
        // Priority should be:
        //    return Constants.HIGHEST_RECOGNITION_PRIORITY;
        // Yann 2004/08/09: Priority.
        // Priorities as they are now make more sense.
        return Constants.LOWEST_RECOGNITION_PRIORITY;
    }
}