Package org.bndtools.builder.handlers.baseline

Source Code of org.bndtools.builder.handlers.baseline.BaselineErrorHandler

package org.bndtools.builder.handlers.baseline;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.bndtools.api.ILogger;
import org.bndtools.api.Logger;
import org.bndtools.build.api.AbstractBuildErrorDetailsHandler;
import org.bndtools.build.api.MarkerData;
import org.bndtools.utils.jdt.ASTUtil;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.ui.IMarkerResolution;

import aQute.bnd.build.Project;
import aQute.bnd.differ.Baseline.Info;
import aQute.bnd.properties.IRegion;
import aQute.bnd.properties.LineType;
import aQute.bnd.properties.PropertiesLineReader;
import aQute.bnd.service.diff.Delta;
import aQute.bnd.service.diff.Diff;
import aQute.bnd.service.diff.Tree;
import aQute.bnd.service.diff.Type;
import aQute.lib.io.IO;
import aQute.service.reporter.Report.Location;

public class BaselineErrorHandler extends AbstractBuildErrorDetailsHandler {

    private static final String PACKAGEINFO = "packageinfo";
    private static final String PROP_SUGGESTED_VERSION = "suggestedVersion";

    private static final ILogger logger = Logger.getLogger(BaselineErrorHandler.class);

    @Override
    public List<MarkerData> generateMarkerData(IProject project, Project model, Location location) throws Exception {
        List<MarkerData> result = new LinkedList<MarkerData>();

        Info baselineInfo = (Info) location.details;
        IJavaProject javaProject = JavaCore.create(project);

        result.addAll(generatePackageInfoMarkers(baselineInfo, javaProject, location.message));
        result.addAll(generateStructuralChangeMarkers(baselineInfo, javaProject));

        return result;
    }

    List<MarkerData> generatePackageInfoMarkers(Info baselineInfo, IJavaProject javaProject, String message) throws JavaModelException {
        for (IClasspathEntry entry : javaProject.getRawClasspath()) {
            if (IClasspathEntry.CPE_SOURCE == entry.getEntryKind()) {
                IPath entryPath = entry.getPath();
                IPath pkgPath = entryPath.append(baselineInfo.packageName.replace('.', '/'));

                // TODO: handle package-info.java

                IPath pkgInfoPath = pkgPath.append(PACKAGEINFO);
                IFile pkgInfoFile = javaProject.getProject().getWorkspace().getRoot().getFile(pkgInfoPath);
                if (pkgInfoFile != null && pkgInfoFile.exists()) {
                    Map<String,Object> attribs = new HashMap<String,Object>();
                    attribs.put(IMarker.MESSAGE, message.trim());
                    attribs.put(PROP_SUGGESTED_VERSION, baselineInfo.suggestedVersion.toString());

                    LineLocation lineLoc = findVersionLocation(pkgInfoFile.getLocation().toFile());
                    if (lineLoc != null) {
                        attribs.put(IMarker.LINE_NUMBER, lineLoc.lineNum);
                        attribs.put(IMarker.CHAR_START, lineLoc.start);
                        attribs.put(IMarker.CHAR_END, lineLoc.end);
                    }

                    return Collections.singletonList(new MarkerData(pkgInfoFile, attribs, true));
                }
            }
        }

        return Collections.emptyList();
    }

    List<MarkerData> generateStructuralChangeMarkers(Info baselineInfo, IJavaProject javaProject) throws JavaModelException {
        List<MarkerData> markers = new LinkedList<MarkerData>();

        Delta packageDelta = baselineInfo.packageDiff.getDelta();

        // Iterate into the package member diffs
        for (Diff pkgMemberDiff : baselineInfo.packageDiff.getChildren()) {
            // Skip deltas that have lesser significance than the overall package delta
            if (pkgMemberDiff.getDelta().ordinal() < packageDelta.ordinal())
                continue;

            if (Delta.ADDED == pkgMemberDiff.getDelta()) {
                @SuppressWarnings("unused")
                Tree pkgMember = pkgMemberDiff.getNewer();
                //                markers.addAll(generateAddedTypeMarker(javaProject, pkgMember.getName(), pkgMember.ifAdded()));
            } else if (Delta.REMOVED == pkgMemberDiff.getDelta()) {} else {
                Tree pkgMember = pkgMemberDiff.getOlder();
                if (pkgMember != null && (Type.INTERFACE == pkgMember.getType() || Type.CLASS == pkgMember.getType())) {
                    String className = pkgMember.getName();

                    // Iterate into the class member diffs
                    for (Diff classMemberDiff : pkgMemberDiff.getChildren()) {
                        // Skip deltas that have lesser significance than the overall package delta (again)
                        if (classMemberDiff.getDelta().ordinal() < packageDelta.ordinal())
                            continue;

                        if (Delta.ADDED == classMemberDiff.getDelta()) {
                            Tree classMember = classMemberDiff.getNewer();
                            if (Type.METHOD == classMember.getType())
                                markers.addAll(generateAddedMethodMarker(javaProject, className, classMember.getName(), classMember.ifAdded()));
                        } else if (Delta.REMOVED == classMemberDiff.getDelta()) {
                            Tree classMember = classMemberDiff.getOlder();
                            if (Type.METHOD == classMember.getType()) {
                                markers.addAll(generateRemovedMethodMarker(javaProject, className, classMember.getName(), classMember.ifRemoved()));
                            }
                        }
                    }
                }
            }

        }

        return markers;
    }

    /*
    List<MarkerData> generateAddedTypeMarker(IJavaProject javaProject, String name, Delta ifAdded) {
        // TODO Auto-generated method stub
        return null;
    }
    */

    List<MarkerData> generateAddedMethodMarker(IJavaProject javaProject, String className, final String methodName, final Delta requiresDelta) throws JavaModelException {
        final List<MarkerData> markers = new LinkedList<MarkerData>();
        final CompilationUnit ast = createAST(javaProject, className);
        ast.accept(new ASTVisitor() {
            @Override
            public boolean visit(MethodDeclaration methodDecl) {
                String signature = ASTUtil.buildMethodSignature(methodDecl);
                if (signature.equals(methodName)) {
                    // Create the marker attribs here
                    Map<String,Object> attribs = new HashMap<String,Object>();
                    attribs.put(IMarker.CHAR_START, methodDecl.getStartPosition());
                    attribs.put(IMarker.CHAR_END, methodDecl.getStartPosition() + methodDecl.getLength());

                    String message = String.format("This method was added, which requires a %s change to the package.", requiresDelta);
                    attribs.put(IMarker.MESSAGE, message);

                    markers.add(new MarkerData(ast.getJavaElement().getResource(), attribs, false));
                }

                return false;
            }
        });
        return markers;
    }

    List<MarkerData> generateRemovedMethodMarker(IJavaProject javaProject, final String className, final String methodName, final Delta requiresDelta) throws JavaModelException {
        final List<MarkerData> markers = new LinkedList<MarkerData>();
        final CompilationUnit ast = createAST(javaProject, className);
        ast.accept(new ASTVisitor() {
            @Override
            public boolean visit(TypeDeclaration typeDecl) {
                ITypeBinding typeBinding = typeDecl.resolveBinding();
                if (typeBinding != null) {
                    if (typeBinding.getBinaryName().equals(className)) {
                        Map<String,Object> attribs = new HashMap<String,Object>();
                        SimpleName nameNode = typeDecl.getName();
                        attribs.put(IMarker.CHAR_START, nameNode.getStartPosition());
                        attribs.put(IMarker.CHAR_END, nameNode.getStartPosition() + nameNode.getLength());

                        String message = String.format("The method '%s' was removed, which requires a %s change to the package.", methodName, requiresDelta);
                        attribs.put(IMarker.MESSAGE, message);

                        markers.add(new MarkerData(ast.getJavaElement().getResource(), attribs, false));
                        return false;
                    }
                }
                return true;
            }
        });

        return markers;
    }

    @Override
    public List<IMarkerResolution> getResolutions(IMarker marker) {
        List<IMarkerResolution> result = new LinkedList<IMarkerResolution>();

        final String suggestedVersion = marker.getAttribute(PROP_SUGGESTED_VERSION, null);
        if (suggestedVersion != null) {
            result.add(new IMarkerResolution() {
                @Override
                public void run(IMarker marker) {
                    final IFile file = (IFile) marker.getResource();
                    final IWorkspace workspace = file.getWorkspace();
                    try {
                        workspace.run(new IWorkspaceRunnable() {
                            @Override
                            public void run(IProgressMonitor monitor) throws CoreException {
                                String input = "version " + suggestedVersion;
                                ByteArrayInputStream stream = new ByteArrayInputStream(input.getBytes());
                                file.setContents(stream, false, true, monitor);
                            }
                        }, null);
                    } catch (CoreException e) {
                        logger.logError("Error applying baseline version quickfix.", e);
                    }
                }

                @Override
                public String getLabel() {
                    return "Change package version to " + suggestedVersion;
                }
            });

        }

        return result;
    }

    @Override
    public List<ICompletionProposal> getProposals(IMarker marker) {
        List<ICompletionProposal> proposals = new LinkedList<ICompletionProposal>();

        String suggestedVersion = marker.getAttribute(PROP_SUGGESTED_VERSION, null);
        int start = marker.getAttribute(IMarker.CHAR_START, 0);
        int end = marker.getAttribute(IMarker.CHAR_END, 0);
        CompletionProposal proposal = new CompletionProposal("version " + suggestedVersion, start, end - start, end, null, "Change package version to " + suggestedVersion, null, null);
        proposals.add(proposal);

        return proposals;
    }

    private LineLocation findVersionLocation(File file) {
        String content;
        try {
            content = IO.collect(file);
            PropertiesLineReader reader = new PropertiesLineReader(content);

            int lineNum = 1;
            LineType type = reader.next();
            while (type != LineType.eof) {
                if (type == LineType.entry) {
                    String key = reader.key();
                    if ("version".equals(key)) {
                        LineLocation loc = new LineLocation();
                        loc.lineNum = lineNum;
                        IRegion region = reader.region();
                        loc.start = region.getOffset();
                        loc.end = region.getOffset() + region.getLength();
                        return loc;
                    }
                }
                type = reader.next();
                lineNum++;
            }
        } catch (Exception e) {
            // ignore
        }

        return null;
    }
}
TOP

Related Classes of org.bndtools.builder.handlers.baseline.BaselineErrorHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.