de.plugins.eclipse.depclipse.JDependAdapter.java Source code

Java tutorial

Introduction

Here is the source code for de.plugins.eclipse.depclipse.JDependAdapter.java

Source

/*******************************************************************************
 * Copyright (c) 2004 Andrei Loskutov.
 * Copyright (c) 2010 Jens Cornelis
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the BSD License
 * which accompanies this distribution, and is available at
 * http://www.opensource.org/licenses/bsd-license.php
 * Contributor:  Jens Cornelis - initial API and implementation
 *               Andrei Loskutov - some methods from original JDepend4Eclipse implementation
 *******************************************************************************/
package de.plugins.eclipse.depclipse;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.preference.IPreferenceStore;
import org.xml.sax.SAXParseException;

import com.thoughtworks.xstream.converters.ConversionException;

import de.plugins.eclipse.depclipse.model.JDependData;
import de.plugins.eclipse.depclipse.model.TreeFolder;
import de.plugins.eclipse.depclipse.model.TreeLeaf;
import de.plugins.eclipse.depclipse.model.TreeObject;
import de.plugins.eclipse.depclipse.preferences.JDependPreferenceConstants;
import de.plugins.eclipse.depclipse.rules.ProjectRules;

import jdepend.framework.JDepend;
import jdepend.framework.JavaClass;
import jdepend.framework.JavaPackage;
import jdepend.framework.PackageComparator;

/**
 * Adapter for JDepend. 
 * 
 * @author Andrei Loskutov
 * @author Jens Cornelis
 */
public class JDependAdapter {

    /**
     * Runs JDepend for the given Resources. Results are written to
     * the given JDependData-Instance.
     * 
     * @throws IOException
     * @throws CoreException
     * @throws SAXParseException 
     * @throws ConversionException
     */
    public void startAnalyze(JDependData jdependData, IResource[] resource)
            throws IOException, CoreException, SAXParseException, ConversionException {

        IPreferenceStore preferences = DepclipsePlugin.getDefault().getPreferenceStore();

        TreeFolder newRoot = new TreeFolder();
        newRoot.setIResource(resource[0]);

        String[] activeFilters = preferences.getString(JDependPreferenceConstants.PREF_ACTIVE_FILTERS_LIST)
                .split(","); //$NON-NLS-1$
        jdependData.setFilters(activeFilters);

        // set the filters for this JDepend instance
        JDepend jdepend = new JDepend(jdependData.getFilter());

        jdependData.clearResourceMap();

        for (int i = 0; i < resource.length; i++) {
            TreeFolder[] tp = createTree(jdependData, resource[i]);
            for (int j = 0; j < tp.length; j++) {
                // tree object check if child exist
                if (tp[j].hasChildren()) {
                    newRoot.addChild(tp[j]);
                }
            }
        }

        List<JavaPackage> packages = runJDepend(jdepend, newRoot.getChildren());
        updateCycleInfo(newRoot, packages);

        // if the preference is set to use ProhibitedDependencies functions,
        // the ProjectRules and ProhibitedDependencies are updated
        if (preferences.getBoolean(JDependPreferenceConstants.USE_FORBIDDEN_DEPENDENCIES)) {
            updateProhibitedDependencies(newRoot, packages);
        }

        jdependData.setRoot(newRoot);
        jdependData.setJavaPackages(packages);

        // set model dirty
        DepclipsePlugin.getJDependData().setDirty();
    }

    private void updateProhibitedDependencies(TreeFolder newRoot, List<JavaPackage> packages)
            throws IOException, CoreException, SAXParseException, ConversionException {
        // deserialize ProjectRules and update them
        ProjectRules oldRules = DepclipsePlugin.getProjectRules(newRoot.getIResource().getProject());
        oldRules.updateProjectRules(packages);

        for (JavaPackage jp : packages) {
            TreeFolder tmpFolder = (TreeFolder) newRoot.findChild(jp);
            if (tmpFolder != null) {
                tmpFolder.checkAgainstDependencyRule(oldRules, jp.getEfferents());
                if (tmpFolder.getBadDependencies().size() > 0) {
                    oldRules.updateProhibitedPackageRule(tmpFolder.getPackageName(),
                            tmpFolder.getBadDependencies());
                }
                Set<JavaClass> classes = jp.getClasses();
                Map<String, JavaClass> classMap = new HashMap<String, JavaClass>();

                // TODO: Smells!
                for (JavaClass clazz : classes.toArray(new JavaClass[0])) {
                    // Quick'n'Dirty solution for not looking at internal classes
                    if (!clazz.getName().contains("$")) {
                        classMap.put(clazz.getSourceFile(), clazz);
                    }
                }

                for (TreeObject to : tmpFolder.getChildren()) {
                    // Check, if classMap contains this TreeObject/Class.
                    // This caused Exception, when Package contains class-file without implementation of class
                    // (e.g. if the whole class is commented).
                    if (classMap.containsKey(to.getName())) {
                        to.checkAgainstDependencyRule(oldRules, classMap.get(to.getName()).getImportedPackages());
                    }
                }
            }
        }
        // save the Rules back to the file
        DepclipsePlugin.setProjectRules(newRoot.getIResource().getProject(), oldRules);
    }

    private void updateCycleInfo(TreeFolder newRoot, List<JavaPackage> packages) {
        // update cycle info
        // set cycle to true, if one of packages is under the founded tree root
        for (JavaPackage jp : packages) {
            boolean cycle = jp.containsCycle();
            if (cycle) {
                if (jp.getName().length() == 0) {
                    newRoot.setContainsCycle(cycle);
                    continue;
                }
                TreeObject child = newRoot.findChild(jp);
                if (child != null && !child.isLeaf()) {
                    ((TreeFolder) child).setContainsCycle(cycle);
                }
            }
        }
    }

    /**
     * Create object tree and initialize map with new IResource->TreeObject
     * pairs.
     * 
     * @param resource
     * @return TreeParent
     */
    private TreeFolder[] createTree(JDependData jdependData, IResource resource) {
        if (resource.getType() != IResource.FOLDER) {
            return new TreeFolder[0];
        }
        IContainer folder = (IContainer) resource;

        IResource[] resources = null;

        try {
            resources = folder.members();
        } catch (CoreException e) {
            DepclipsePlugin.handle(e);
        }

        if (resources == null || resources.length == 0) {
            return new TreeFolder[0];
        }

        boolean isPackageRoot = false;
        IJavaElement javaElement = JavaCore.create(folder);

        if (javaElement != null) {
            try {
                isPackageRoot = TreeObject.isPackageRoot(javaElement.getJavaProject(), folder);
            } catch (JavaModelException e) {

            }
        } else {
            isPackageRoot = false;
        }

        if (!isPackageRoot && jdependData.resourceMapContains(folder)) {
            return new TreeFolder[0];
        }

        TreeFolder tree = (TreeFolder) jdependData.getFromResourceMap(folder);
        ArrayList<TreeFolder> treeRoots = null;
        // add parent package, if not exist
        if (tree == null) {
            tree = new TreeFolder(javaElement);
            treeRoots = new ArrayList<TreeFolder>();
            treeRoots.add(tree);
            jdependData.putToResourceMap(folder, tree);

        }
        if (treeRoots == null) {
            return new TreeFolder[0];
        }
        TreeFolder[] results;
        TreeLeaf tleaf;
        IJavaElement javaChild;
        String tname;
        for (int i = 0; i < resources.length; i++) {
            if (resources[i].getType() == IResource.FOLDER) {
                results = createTree(jdependData, resources[i]);
                for (int j = 0; j < results.length; j++) {
                    if (!treeRoots.contains(results[j])) {
                        treeRoots.add(results[j]);
                    }
                }
            } else {
                tname = resources[i].getName();
                if (tname.endsWith(".java")) { //$NON-NLS-1$
                    javaChild = JavaCore.create(resources[i]);
                    if (javaChild == null) {
                        continue;
                    }
                    tleaf = new TreeLeaf(javaChild);
                    jdependData.putToResourceMap(resources[i], tleaf);
                    tree.addChild(tleaf);
                } else if (tname.endsWith(".class")) { //$NON-NLS-1$
                    tleaf = new TreeLeaf(resources[i]);
                    jdependData.putToResourceMap(resources[i], tleaf);
                    tree.addChild(tleaf);
                }
            }
        }

        return (TreeFolder[]) treeRoots.toArray(new TreeFolder[treeRoots.size()]);
    }

    private List<JavaPackage> runJDepend(JDepend jdepend, TreeObject[] treeObjects) {
        for (int i = 0; i < treeObjects.length; i++) {
            try {
                if (!treeObjects[i].isLeaf()) {
                    TreeFolder folder = (TreeFolder) treeObjects[i];
                    // add roots
                    ArrayList<String> dirs = folder.getClassesLocation();
                    for (int j = 0; j < dirs.size(); j++) {
                        jdepend.addDirectory("" + dirs.get(j)); //$NON-NLS-1$
                    }
                }
            } catch (Exception e) {
                // if directory doesn't exist, may be project need to be rebuild
                DepclipsePlugin.handle(e);
            }
        }
        final List<JavaPackage> packages = new ArrayList<JavaPackage>(jdepend.analyze());

        Collections.sort(packages, new PackageComparator(PackageComparator.byName()));
        return packages;
    }
}