com.feup.contribution.druid.data.DruidProject.java Source code

Java tutorial

Introduction

Here is the source code for com.feup.contribution.druid.data.DruidProject.java

Source

/*
 * This file is part of drUID.
 * 
 * drUID 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.
 * 
 * drUID 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 drUID.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.feup.contribution.druid.data;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;

import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

import com.feup.contribution.druid.DruidPlugin;
import com.feup.contribution.druid.diagram.DotDiagramCreator;
import com.feup.contribution.druid.listeners.ProjectListener;
import com.feup.contribution.druid.tester.DruidTester;
import com.feup.contribution.druid.util.MethodSignatureCreator;

public class DruidProject {
    private ArrayList<DruidUnit> units;
    private ArrayList<ProjectListener> listeners = new ArrayList<ProjectListener>();
    private IJavaProject project;

    public static final String FEATURE_BROKEN = "com.feup.contribution.druid.featureBroken";
    public static final String FEATURE_NOT_BROKEN = "com.feup.contribution.druid.featureNotBroken";
    public static final String FAILED_TEST = "com.feup.contribution.druid.failedTest";
    public static final String DEPENDENCY_DEPRECATED = "com.feup.contribution.druid.dependencyDeprecated";

    public DruidProject(IJavaProject project) {
        units = new ArrayList<DruidUnit>();
        listeners = new ArrayList<ProjectListener>();
        this.setProject(project);
    }

    private void setProject(IJavaProject project) {
        this.project = project;
    }

    public Collection<DruidUnit> getUnits() {
        return units;
    }

    private DruidUnit getUnit(String unitName) {
        for (DruidUnit unit : units) {
            if (unit.getName().equals(unitName))
                return unit;
        }
        return null;
    }

    public void updateDiagram() {
        new DotDiagramCreator(this).drawDiagram();
    }

    public void builderDone() {
        updateDiagram();
        for (ProjectListener listener : listeners) {
            listener.projectChanged(this);
        }
    }

    public void addProjectListener(ProjectListener listener) {
        listeners.add(listener);
    }

    public void addFeature(String unitName, IMethod method, String featureName) throws JavaModelException {
        String methodSignature = MethodSignatureCreator.createSignature(method);
        DruidUnit unit = getUnit(unitName);
        if (unit == null) {
            unit = new DruidUnit(unitName, this);
            units.add(unit);
        }
        unit.addFeature(method, methodSignature, featureName);
    }

    public void removeAllFeatures() {
        units.clear();
    }

    public boolean addDepends(String unitName, ArrayList<String> featureNames, String dUnitName,
            String dFeatureName, IResource resource, int offset, int length) {
        DruidUnit unit = getUnit(unitName);
        if (unit == null)
            return false;
        DruidFeature dFeature = getFeature(dUnitName, dFeatureName);
        if (dFeature != null)
            unit.addDepends(featureNames, dFeature, resource, offset, length);
        else
            return false;
        return true;
    }

    private DruidFeature getFeature(String unitName, String featureName) {
        DruidUnit unit = getUnit(unitName);
        if (unit == null)
            return null;
        return unit.getFeature(featureName);
    }

    public boolean addTest(IMethod method, String tUnitName, String tFeatureName) {
        DruidFeature tFeature = getFeature(tUnitName, tFeatureName);
        if (tFeature != null)
            tFeature.addTests(method);
        else
            return false;
        return true;
    }

    private Shell getShell() {
        IWorkbench workbench = PlatformUI.getWorkbench();
        IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
        if (window == null)
            return null;
        return window.getShell();
    }

    public boolean detectInteractions() {
        ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell());
        try {
            dialog.run(true, true, new IRunnableWithProgress() {
                @Override
                public void run(IProgressMonitor monitor) throws InvocationTargetException {
                    detectInteractionsBuild(monitor);
                }
            });
        } catch (InterruptedException e) {
            return false;
        } catch (InvocationTargetException e) {
            return false;
        }
        return true;
    }

    public void detectInteractionsBuild(IProgressMonitor monitor) {
        ArrayList<DruidComponent> components = DruidComponent.getOrderedComponents(units);
        ArrayList<DruidComponent> toCompile = new ArrayList<DruidComponent>();

        DruidTester tester = new DruidTester();

        String cp = getClasspath();

        removeDeprecatedBy();
        removeOldMarkers();

        monitor.beginTask("Detect Interactions", components.size() + 1);
        monitor.worked(1);
        int currentComponent = 1;
        for (DruidComponent component : components) {
            if (monitor.isCanceled())
                return;
            monitor.subTask(component.toString());
            toCompile.add(component);

            if (testDeprecatedFeatures(component))
                return;

            for (DruidUnit druidUnit : component.getUnits())
                druidUnit.addDeprecatedBy();

            tester.setUpTest(toCompile);
            tester.compile(cp);

            for (DruidComponent druidComponent : toCompile) {
                for (DruidUnit druidUnit : druidComponent.getUnits()) {
                    for (DruidFeature druidFeature : druidUnit.getFeatures()) {
                        for (DruidTest druidTest : druidFeature.getTests()) {
                            boolean result = tester.test(druidTest.getMethod(), cp);

                            try {
                                if (!result && component.getUnits().contains(druidUnit)) {
                                    String message = "Unit " + component.getUnits().get(0).getName()
                                            + ": test failed for feature " + druidFeature;
                                    IMethod method = druidTest.getMethod();
                                    addMarker(FAILED_TEST, message, method.getResource(),
                                            method.getNameRange().getOffset(), method.getNameRange().getLength());
                                    monitor.done();
                                    showErrorDialog("Failed Test", message, tester.getDetails());
                                    return;
                                } else if (!druidFeature.isDeprecated() && !result) {
                                    String message = "Unit " + component.getUnits().get(0).getName()
                                            + " breaks feature " + druidFeature;
                                    IMethod method = druidTest.getMethod();
                                    addMarker(FEATURE_BROKEN, message, method.getResource(),
                                            method.getNameRange().getOffset(), method.getNameRange().getLength());
                                    monitor.done();
                                    showErrorDialog("Feature Broken", message, "");
                                    return;
                                } else if (druidFeature.isDeprecated() && result) {
                                    String message = "Unit " + component.getUnits().get(0).getName()
                                            + " doesn't break feature " + druidFeature;
                                    DruidDeprecate deprecate = druidFeature.getDeprecatedBy().get(0);
                                    addMarker(FEATURE_NOT_BROKEN, message, deprecate.getResource(),
                                            deprecate.getOffset(), deprecate.getLength());
                                    monitor.done();
                                    showErrorDialog("Feature Not Broken", message, "");
                                    return;
                                }
                            } catch (JavaModelException e) {
                                DruidPlugin.getPlugin().logException(e);
                            }
                        }
                    }
                }
                tester.tearDown();
            }
            monitor.worked(++currentComponent);
        }
        monitor.done();
    }

    private void showErrorDialog(final String title, final String message, final String details) {
        Display.getDefault().asyncExec(new Runnable() {
            @Override
            public void run() {
                MessageDialog.openError(getShell(), title, message + "\n\n" + details);
            }
        });
    }

    private void addMarker(String type, String message, IResource resource, int offset, int length) {
        try {
            IMarker marker = resource.createMarker(type);
            marker.setAttribute(IMarker.MESSAGE, message);
            marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
            marker.setAttribute(IMarker.CHAR_START, offset);
            marker.setAttribute(IMarker.CHAR_END, offset + length);
        } catch (CoreException e) {
            DruidPlugin.getPlugin().logException(e);
        }
    }

    private void removeDeprecatedBy() {
        for (DruidUnit unit : units)
            unit.removeDeprecatedBy();
    }

    private void removeOldMarkers() {
        try {
            for (DruidUnit unit : units)
                for (DruidFeature feature : unit.getFeatures()) {
                    for (DruidMethod method : feature.getMethods()) {
                        method.getMethod().getResource().deleteMarkers(DEPENDENCY_DEPRECATED, true,
                                IResource.DEPTH_INFINITE);
                        method.getMethod().getResource().deleteMarkers(FEATURE_NOT_BROKEN, true,
                                IResource.DEPTH_INFINITE);
                    }

                    for (DruidTest test : feature.getTests()) {
                        test.getMethod().getResource().deleteMarkers(FEATURE_BROKEN, true,
                                IResource.DEPTH_INFINITE);
                        test.getMethod().getResource().deleteMarkers(FAILED_TEST, true, IResource.DEPTH_INFINITE);
                    }
                }
        } catch (CoreException e) {
            DruidPlugin.getPlugin().logException(e);
        }
    }

    private String getClasspath() {
        String cp = "";
        try {
            IClasspathEntry[] classpath = project.getJavaProject().getResolvedClasspath(false);
            for (IClasspathEntry classpathEntry : classpath) {
                if (cp.equals(""))
                    cp = classpathEntry.getPath().toOSString();
                else
                    cp += ":" + classpathEntry.getPath().toOSString();
            }
        } catch (JavaModelException e) {
            DruidPlugin.getPlugin().logException(e);
        }
        return cp;
    }

    private boolean testDeprecatedFeatures(DruidComponent component) {
        for (DruidUnit druidUnit : component.getUnits())
            for (DruidFeature feature : druidUnit.getFeatures()) {
                for (DruidDependency dependency : feature.getDependecies()) {
                    if (dependency.getDependee().isDeprecated()) {
                        String message = "Feature " + dependency.getDependee() + " used by "
                                + dependency.getDependent() + " deprecated by "
                                + dependency.getDependee().getDeprecatedBy();

                        try {
                            IMarker marker = dependency.getResource().createMarker(DEPENDENCY_DEPRECATED);
                            marker.setAttribute(IMarker.MESSAGE, message);
                            marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
                            marker.setAttribute(IMarker.CHAR_START, dependency.getOffset());
                            marker.setAttribute(IMarker.CHAR_END, dependency.getOffset() + dependency.getLength());
                            showErrorDialog("Feature Deprecated", message, "");
                        } catch (CoreException e) {
                            DruidPlugin.getPlugin().logException(e);
                        }

                        return true;
                    }
                }
            }
        return false;
    }

    public String getName() {
        return project.getElementName();
    }

    public IJavaProject getIProject() {
        return project;
    }

    public boolean addDeprecate(String unitName, ArrayList<String> featureNames, String dUnitName,
            String dFeatureName, IResource resource, int offset, int length) {
        DruidUnit unit = getUnit(unitName);
        if (unit == null)
            return false;
        DruidFeature dFeature = getFeature(dUnitName, dFeatureName);
        if (dFeature != null)
            unit.addDeprecates(featureNames, dFeature, resource, offset, length);
        else
            return false;
        return true;
    }

    public ArrayList<String> getFeatureNames(String unitName, String prefix) {
        ArrayList<String> names = new ArrayList<String>();
        Collection<DruidUnit> units = getUnits();
        for (DruidUnit unit : units) {
            Collection<DruidFeature> features = unit.getFeatures();
            for (DruidFeature feature : features) {
                String featureName = "";
                if (unit.getName().equals(unitName))
                    featureName = feature.getName();
                else
                    featureName = feature.getUnit().getName() + "." + feature.getName();
                if (featureName.startsWith(prefix))
                    names.add(featureName);
            }
        }
        return names;
    }

    public ArrayList<String> getFeatureNames(String unitName, IMethod method) throws JavaModelException {
        for (DruidUnit unit : units)
            if (unit.getName().equals(unitName))
                return unit.getFeaturesWithMethod(method);
        return new ArrayList<String>();
    }
}