Package org.springframework.ide.eclipse.quickfix

Source Code of org.springframework.ide.eclipse.quickfix.QuickfixUtils

/*******************************************************************************
*  Copyright (c) 2012 VMware, Inc.
*  All rights reserved. This program and the accompanying materials
*  are made available under the terms of the Eclipse Public License v1.0
*  which accompanies this distribution, and is available at
*  http://www.eclipse.org/legal/epl-v10.html
*
*  Contributors:
*      VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.quickfix;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Assignment;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IBinding;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ModifierChangeCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.NewVariableCorrectionProposal;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
import org.eclipse.wst.sse.ui.StructuredTextEditor;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;
import org.eclipse.wst.xml.core.internal.document.AttrImpl;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
import org.springframework.ide.eclipse.beans.core.model.IBeansConfig;
import org.springframework.ide.eclipse.config.core.IConfigEditor;
import org.springframework.ide.eclipse.config.core.schemas.BeansSchemaConstants;
import org.springframework.ide.eclipse.core.java.JdtUtils;
import org.springframework.ide.eclipse.core.model.IResourceModelElement;
import org.springframework.ide.eclipse.quickfix.proposals.CreateNewMethodQuickFixProposal;
import org.springframework.ide.eclipse.quickfix.proposals.QuickfixReflectionUtils;
import org.springframework.ide.eclipse.quickfix.validator.BeanValidator;
import org.springsource.ide.eclipse.commons.core.StatusHandler;
import org.w3c.dom.Attr;
import org.w3c.dom.Node;

/**
* Utility class with helper methods for calculating quick fixes for bean
* configuration files.
* @author Terry Denney
* @author Leo Dos Santos
* @author Christian Dupuis
* @since 2.0
*/
public class QuickfixUtils {

  private static class ASTFinder extends ASTVisitor {

    private MethodInvocation methodInvo;

    private ClassInstanceCreation constInvo;

    private Assignment assignment;

    private MethodDeclaration methodDecl;

    private IMethod methodToMatch;

    private String classNameToMatch;

    private TypeDeclaration typeDecl;

    private ASTFinder() {

    }

    private ASTFinder(IMethod methodToMatch) {
      this.methodToMatch = methodToMatch;
    }

    private ASTFinder(String classNameToMatch) {
      int pos = classNameToMatch.lastIndexOf(".");
      if (pos > 0) {
        this.classNameToMatch = classNameToMatch.substring(pos + 1);
      }
      else {
        this.classNameToMatch = classNameToMatch;
      }
    }

    private ClassInstanceCreation getConstructorInvocation() {
      return constInvo;
    }

    private SimpleName getFieldAccess() {
      if (assignment == null) {
        return null;
      }
      Expression lhs = assignment.getLeftHandSide();
      if (lhs instanceof SimpleName) {
        return (SimpleName) lhs;
      }

      if (lhs instanceof QualifiedName) {
        QualifiedName qn = (QualifiedName) lhs;
        return qn.getName();
      }
      return null;
    }

    private MethodDeclaration getMethodDeclaration() {
      return methodDecl;
    }

    private MethodInvocation getMethodInvocation() {
      return methodInvo;
    }

    private TypeDeclaration getTypeDeclaration() {
      return typeDecl;
    }

    @Override
    public boolean visit(Assignment node) {
      this.assignment = node;
      return false;
    }

    @Override
    public boolean visit(ClassInstanceCreation node) {
      this.constInvo = node;
      return false;
    }

    @Override
    public boolean visit(MethodDeclaration node) {
      if (methodToMatch != null) {
        if (node.getName().getFullyQualifiedName().equals(methodToMatch.getElementName())
            && node.parameters().size() == methodToMatch.getNumberOfParameters()) {
          this.methodDecl = node;
          return false;
        }
      }

      return super.visit(node);
    }

    @Override
    public boolean visit(MethodInvocation node) {
      this.methodInvo = node;
      return false;
    }

    @Override
    public boolean visit(TypeDeclaration node) {
      if (node.getName().getFullyQualifiedName().equals(classNameToMatch)) {
        this.typeDecl = node;
        return false;
      }
      return true;
    }
  }

  // private static QuickfixSupport nodeQuickfixSupport;

  private static QuickfixSupport attributeQuickfixSupport;

  private static ASTParser createASTParser(IJavaProject javaProject, ICompilationUnit cu, int kind) {
    ASTParser parser = ASTParser.newParser(AST.JLS4);
    parser.setKind(kind);
    parser.setSource(cu);
    parser.setResolveBindings(true);
    parser.setProject(javaProject);
    return parser;
  }

  public static void createConstructor(IDocument document, IType targetType, List<String> constructorArgClassNames,
      IJavaProject javaProject) {
    ICompilationUnit cu = targetType.getCompilationUnit();
    if (cu == null) {
      return;
    }

    ITypeBinding typeBinding = QuickfixUtils.getTargetTypeBinding(javaProject, targetType);

    String className = targetType.getFullyQualifiedName();
    ClassInstanceCreation invocationNode = QuickfixUtils.getMockConstructorInvocation(className,
        constructorArgClassNames.toArray(new String[constructorArgClassNames.size()]));
    List<Expression> arguments = QuickfixUtils.getArguments(invocationNode);
    Object constructorProposal = QuickfixReflectionUtils.createNewMethodProposal(targetType.getElementName(), cu,
        invocationNode, arguments, typeBinding, 0, null);
    QuickfixReflectionUtils.applyProposal(constructorProposal, document);
  };

  public static ModifierChangeCorrectionProposal createModifierChangeCorrectionProposal(String className,
      String fieldName, IJavaProject javaProject, String displayString, boolean isStatic) {
    IType type = JdtUtils.getJavaType(javaProject.getProject(), className);
    IField field = type.getField(fieldName);
    IBinding binding = getBinding(javaProject, field, type.getCompilationUnit(), ASTParser.K_COMPILATION_UNIT);
    SimpleName fieldNameNode = getMockFieldAccess(className, fieldName, isStatic);
    return new ModifierChangeCorrectionProposal(fieldName, type.getCompilationUnit(), binding, fieldNameNode,
        Modifier.STATIC, 0, 5, null);
  }

  public static NewVariableCorrectionProposal createNewVariableCorrectionProposal(String className, String fieldName,
      IJavaProject javaProject, String displayString, boolean isStatic) {
    IType type = JdtUtils.getJavaType(javaProject.getProject(), className);
    ITypeBinding typeBinding = getTargetTypeBinding(javaProject, type);
    SimpleName fieldNameNode = getMockFieldAccess(className, fieldName, isStatic);
    return new NewVariableCorrectionProposal(displayString, type.getCompilationUnit(),
        NewVariableCorrectionProposal.FIELD, fieldNameNode, typeBinding, 100,
        JavaPluginImages.get(JavaPluginImages.IMG_FIELD_PUBLIC));

  }

  @SuppressWarnings("unchecked")
  public static List<Expression> getArguments(ClassInstanceCreation constructorInvocation) {
    List<Expression> arguments = new ArrayList<Expression>();
    for (Iterator<Expression> argumentIter = constructorInvocation.arguments().iterator(); argumentIter.hasNext();) {
      Expression argumentExpression = argumentIter.next();
      arguments.add(argumentExpression);
    }
    return arguments;
  }

  @SuppressWarnings("unchecked")
  public static List<Expression> getArguments(MethodInvocation methodInvocation) {
    List<Expression> arguments = new ArrayList<Expression>();
    for (Iterator<Expression> argumentIter = methodInvocation.arguments().iterator(); argumentIter.hasNext();) {
      Expression argumentExpression = argumentIter.next();
      arguments.add(argumentExpression);
    }
    return arguments;
  }

  private static synchronized QuickfixSupport getAttributeQuickfixSupport() {
    if (attributeQuickfixSupport == null) {
      attributeQuickfixSupport = new AttributeQuickfixSupport();
    }
    return attributeQuickfixSupport;
  }

  private static IBinding getBinding(IJavaProject javaProject, IJavaElement javaElement, ICompilationUnit cu, int kind) {
    ASTParser bindingParser = createASTParser(javaProject, cu, kind);
    IBinding[] bindings = bindingParser.createBindings(new IJavaElement[] { javaElement },
        new NullProgressMonitor());
    if (bindings != null && bindings.length > 0) {
      return bindings[0];
    }
    return null;
  }

  public static CompilationUnit getCompilationUnitAST(IJavaProject javaProject, ICompilationUnit cu) {
    ASTParser parser = createASTParser(javaProject, cu, ASTParser.K_COMPILATION_UNIT);
    ASTNode ast = parser.createAST(null);
    if (ast instanceof CompilationUnit) {
      return (CompilationUnit) ast;
    }
    return null;
  }

  public static String getConfigName(IResource resource) {
    return resource.getProjectRelativePath().toString();
  }

  public static IDocument getDocument(IMarker marker) {
    IWorkbench workbench = PlatformUI.getWorkbench();
    IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
    IWorkbenchPage page = window.getActivePage();

    IEditorPart editor = null;
    if (marker.getResource() instanceof IFile) {
      FileEditorInput fileInput = new FileEditorInput((IFile) marker.getResource());
      editor = page.findEditor(fileInput);

      if (editor == null) {
        try {
          editor = IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(),
              (IFile) marker.getResource());
        }
        catch (PartInitException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }

      if (editor instanceof IConfigEditor) {
        IConfigEditor configEditor = (IConfigEditor) editor;
        return configEditor.getTextViewer().getDocument();
      }
      else if (editor instanceof MultiPageEditorPart) {
        MultiPageEditorPart multiEditor = (MultiPageEditorPart) editor;
        IEditorPart[] editors = multiEditor.findEditors(fileInput);
        for (IEditorPart e : editors) {
          if (e instanceof StructuredTextEditor) {
            return ((StructuredTextEditor) e).getDocumentProvider().getDocument(fileInput);
          }
        }
      }
      else if (editor instanceof AbstractDecoratedTextEditor) {
        return ((AbstractDecoratedTextEditor) editor).getDocumentProvider().getDocument(fileInput);
      }
    }
    return null;
  }

  public static IDOMNode getEnclosingBeanNode(IDOMNode node) {
    if (node == null) {
      return null;
    }

    String localName = node.getLocalName();
    if (localName != null && localName.equals(BeansSchemaConstants.ELEM_BEAN)) {
      return node;
    }

    Node parentNode = node.getParentNode();
    if (parentNode instanceof IDOMNode) {
      return getEnclosingBeanNode((IDOMNode) parentNode);
    }
    return null;
  }

  public static IMethodBinding getMethodBinding(IJavaProject javaProject, IMethod method) {
    IBinding binding = getBinding(javaProject, method, method.getCompilationUnit(),
        ASTParser.K_CLASS_BODY_DECLARATIONS);
    if (binding != null && binding instanceof IMethodBinding) {
      return (IMethodBinding) binding;
    }
    return null;
  }

  public static MethodDeclaration getMethodDecl(IMethod method) {
    ASTParser parser = createASTParser(method.getJavaProject(), method.getCompilationUnit(),
        ASTParser.K_COMPILATION_UNIT);
    ASTNode ast = parser.createAST(null);
    if (ast instanceof CompilationUnit) {
      CompilationUnit cu = (CompilationUnit) ast;
      ASTFinder visitor = new ASTFinder(method);
      cu.accept(visitor);
      return visitor.getMethodDeclaration();
    }
    return null;
  }

  public static ClassInstanceCreation getMockConstructorInvocation(String className, String[] argTypes) {
    String varSetup = "";
    String methodArgs = "";

    for (int i = 0; i < argTypes.length; i++) {
      String argType = argTypes[i];
      varSetup += argType + " arg" + i + ";";

      if (i > 0) {
        methodArgs += ",";
      }
      methodArgs += "arg" + i;
    }

    String mockConstructorCode = varSetup + "new " + className + "(" + methodArgs + ");";
    return getParsedExpressionFinder(mockConstructorCode, false).getConstructorInvocation();
  }

  public static SimpleName getMockFieldAccess(String className, String fieldName, boolean isStatic) {
    String code = fieldName + "=null;";
    if (isStatic) {
      code = "public static void stub() {" + code + "}";
    }

    return getParsedExpressionFinder(code, isStatic).getFieldAccess();
  }

  public static MethodInvocation getMockMethodInvocation(String methodName, String[] argTypes, String returnType,
      boolean isStatic) {

    String varSetup = "";
    String methodArgs = "";
    for (int i = 0; i < argTypes.length; i++) {
      String argType = argTypes[i];
      varSetup += argType + " arg" + i + ";";

      if (i > 0) {
        methodArgs += ",";
      }
      methodArgs += "arg" + i;
    }

    String mockMethodInvocationCode = methodName + "(" + methodArgs + ");";
    if (returnType != null) {
      mockMethodInvocationCode = varSetup + returnType + " xxx = " + mockMethodInvocationCode;
    }

    if (isStatic) {
      mockMethodInvocationCode = "static {" + mockMethodInvocationCode + "}";
    }

    return getParsedExpressionFinder(mockMethodInvocationCode, isStatic).getMethodInvocation();
  }

  public static CreateNewMethodQuickFixProposal getNewMethodQuickFixProposal(String methodName, String returnType,
      String[] methodParamTypes, IJavaProject javaProject, String className, int offset, int length, String text,
      boolean missingEndQuote, boolean isStatic, String elementType) {
    IType targetType = null;
    try {
      targetType = javaProject.findType(className);
    }
    catch (JavaModelException e) {
      StatusHandler.log(e.getStatus());
      MessageDialog.openError(Display.getDefault().getActiveShell(), "Quick Asssit Error",
          "Could not find class '" + className + "'");
      return null;
    }

    if (targetType == null) {
      StatusHandler
          .log(new Status(Status.ERROR, Activator.PLUGIN_ID, "Could not find class '" + className + "'"));
      MessageDialog.openError(Display.getDefault().getActiveShell(), "Quick Fix Error", "Could not find class '"
          + className + "'");
      return null;
    }

    MethodInvocation mockMethodInvocation = getMockMethodInvocation(methodName, methodParamTypes, returnType,
        isStatic);
    if (mockMethodInvocation == null) {
      return null;
    }

    ITypeBinding typeBinding = getTargetTypeBinding(javaProject, targetType);

    List<Expression> arguments = getArguments(mockMethodInvocation);

    ICompilationUnit cu = targetType.getCompilationUnit();

    if (cu == null || typeBinding == null || arguments == null) {
      return null;
    }

    return new CreateNewMethodQuickFixProposal(offset, length, "Add missing " + elementType + " \'" + text
        + "\' in class \'" + className + "\'", cu, mockMethodInvocation, arguments, typeBinding, 0,
        missingEndQuote);
  }

  private static ASTFinder getParsedExpressionFinder(String toBeParsed, boolean isStatic) {
    ASTParser fooParser = ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
    if (isStatic) {
      fooParser.setKind(ASTParser.K_CLASS_BODY_DECLARATIONS);
    }
    else {
      fooParser.setKind(ASTParser.K_STATEMENTS);
    }
    fooParser.setSource(toBeParsed.toCharArray());
    fooParser.setResolveBindings(true);
    ASTNode parsedAstNode = fooParser.createAST(null);

    ASTFinder visitor = new ASTFinder();
    parsedAstNode.accept(visitor);
    return visitor;
  }

  public static ITypeBinding getTargetTypeBinding(IJavaProject javaProject, IType targetType) {
    IBinding binding = getBinding(javaProject, targetType, targetType.getCompilationUnit(),
        ASTParser.K_COMPILATION_UNIT);
    if (binding != null && binding instanceof ITypeBinding) {
      return (ITypeBinding) binding;
    }
    return null;
  }

  public static BodyDeclaration getTypeDecl(String className, ICompilationUnit compUnit) {
    ASTParser parser = createASTParser(compUnit.getJavaProject(), compUnit, ASTParser.K_COMPILATION_UNIT);
    ASTNode ast = parser.createAST(null);
    if (ast instanceof CompilationUnit) {
      CompilationUnit cu = (CompilationUnit) ast;
      ASTFinder visitor = new ASTFinder(className);
      cu.accept(visitor);
      return visitor.getTypeDeclaration();
    }
    return null;
  }

  private static Set<BeanValidator> getValidators(Node node, Attr attr) {
    return getAttributeQuickfixSupport().getQuickfixValidators(node, attr);
  }

  public static boolean validateAttribute(IBeansConfig config, IResourceModelElement contextElement,
      AttrImpl attrImpl, IDOMNode parent, IReporter reporter, boolean reportError,
      BeansEditorValidator editorValidator) {
    Set<BeanValidator> beanValidators = getValidators(parent, attrImpl);
    boolean errorFound = false;
    for (BeanValidator beanValidator : beanValidators) {
      errorFound |= beanValidator.validateAttributeWithConfig(config, contextElement, attrImpl, parent, reporter,
          reportError, editorValidator);
    }

    return errorFound;
  }

}
TOP

Related Classes of org.springframework.ide.eclipse.quickfix.QuickfixUtils

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.