Package org.springframework.ide.eclipse.quickfix.jdt

Source Code of org.springframework.ide.eclipse.quickfix.jdt.RequestMappingRenameParticipant$PathVariableSourceRange

/*******************************************************************************
*  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.jdt;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
import org.eclipse.jdt.internal.ui.text.correction.AssistContext;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.ProcessorBasedRefactoring;
import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.springframework.ide.eclipse.quickfix.jdt.util.ProposalCalculatorUtil;
import org.springsource.ide.eclipse.commons.core.StatusHandler;


/**
* Rename participant for renaming template URI variable and path variable when
* a method parameter is renamed
*
* @author Terry Denney
*/
public class RequestMappingRenameParticipant extends RenameParticipant {

  private IFile file;

  private String oldName;

  private StringLiteral pathVariableLiteral;

  private PathVariableSourceRange methodPathVariableSourceRange;

  private PathVariableSourceRange typePathVariableSourceRange;

  private class PathVariableSourceRange {

    private final List<Integer> offsets;

    public PathVariableSourceRange() {
      offsets = new ArrayList<Integer>();
    }

    public void addOffset(int offset) {
      offsets.add(offset);
    }

    public List<Integer> getOffsets() {
      return offsets;
    }
  }

  @Override
  public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context)
      throws OperationCanceledException {
    return new RefactoringStatus();
  }

  private void getPositions(TextEdit edit, List<Integer> positions) {
    if (edit instanceof MultiTextEdit) {
      for (TextEdit child : ((MultiTextEdit) edit).getChildren()) {
        getPositions(child, positions);
      }
    }
    else {
      positions.add(edit.getOffset());
    }
  }

  @Override
  public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
    RenameArguments arguments = getArguments();
    String newName = arguments.getNewName();
    MultiTextEdit multiEdit = new MultiTextEdit();

    List<Integer> offsets = new ArrayList<Integer>();
    offsets.addAll(typePathVariableSourceRange.getOffsets());
    offsets.addAll(methodPathVariableSourceRange.getOffsets());
    if (pathVariableLiteral != null) {
      offsets.add(pathVariableLiteral.getStartPosition() + 1);
    }

    // need to look at already refactored positions to make sure offsets are
    // correct
    List<Integer> refactoredPositions = new ArrayList<Integer>();
    ProcessorBasedRefactoring refactoring = getProcessor().getRefactoring();
    if (refactoring != null) {
      TextChange textChange = refactoring.getTextChange(file);
      if (textChange != null) {
        TextEdit edit = textChange.getEdit();
        getPositions(edit, refactoredPositions);
      }
    }

    int changeCount = 0;
    int newLength = newName.length();
    int oldLength = oldName.length();
    int diff = newLength - oldLength;

    for (Integer offset : offsets) {
      List<Integer> toBeRemoved = new ArrayList<Integer>();
      for (int position : refactoredPositions) {
        if (position < offset) {
          changeCount++;

          // once a refactoredPosition is accounted for, remove from
          // list so that it won't be double counted
          toBeRemoved.add(position);
        }
      }
      refactoredPositions.removeAll(toBeRemoved);

      multiEdit.addChild(new ReplaceEdit(offset + changeCount * diff, oldLength, newName));
    }

    if (multiEdit.getChildrenSize() > 0) {
      TextFileChange change = new TextFileChange("", file);
      change.setEdit(multiEdit);
      return change;
    }
    else {
      return null;
    }
  }

  private ICompilationUnit getCompilationUnit(IJavaElement element) {
    if (element == null || element instanceof ICompilationUnit) {
      return (ICompilationUnit) element;
    }
    return getCompilationUnit(element.getParent());
  }

  @Override
  public String getName() {
    return "Rename path variable referenced in @Controller class";
  }

  @SuppressWarnings("unchecked")
  private void addPathVariableSourceRanges(BodyDeclaration decl, String pathVariable,
      PathVariableSourceRange sourceRange) throws JavaModelException {
    if (decl == null) {
      return;
    }

    Set<Annotation> annotations = ProposalCalculatorUtil.findAnnotations("RequestMapping", decl);
    for (Annotation annotation : annotations) {
      Expression value = null;
      if (annotation instanceof SingleMemberAnnotation) {
        value = ((SingleMemberAnnotation) annotation).getValue();
      }
      else if (annotation instanceof NormalAnnotation) {
        List<MemberValuePair> pairs = ((NormalAnnotation) annotation).values();
        for (MemberValuePair pair : pairs) {
          if ("value".equals(pair.getName().getFullyQualifiedName())) {
            value = pair.getValue();
            break;
          }
        }
      }

      if (value instanceof StringLiteral) {
        String uri = ((StringLiteral) value).getLiteralValue();

        int offset = value.getStartPosition() + 1; // skip opening quote
        while (uri != null && uri.length() > 0) {
          int index = uri.indexOf("{" + pathVariable + "}");
          if (index > 0) {
            int pathVariableLength = pathVariable.length();
            sourceRange.addOffset(offset + index + 1);
            offset += index + pathVariableLength + 2;
            uri = uri.substring(index + pathVariableLength + 2);
          }
          else {
            uri = null;
          }
        }
      }
    }
  }

  @Override
  protected boolean initialize(Object element) {
    boolean hasPathVariable = false;

    if (element instanceof ILocalVariable) {
      ILocalVariable variable = (ILocalVariable) element;
      ICompilationUnit compilationUnit = getCompilationUnit(variable);
      file = (IFile) compilationUnit.getResource();

      try {
        ISourceRange sourceRange = variable.getSourceRange();
        AssistContext assistContext = new AssistContext(compilationUnit, null, sourceRange.getOffset(),
            sourceRange.getLength());
        ASTNode node = assistContext.getCoveringNode();

        if (node instanceof SingleVariableDeclaration) {
          SingleVariableDeclaration varDecl = (SingleVariableDeclaration) node;
          Set<Annotation> annotations = ProposalCalculatorUtil.findAnnotations("PathVariable", varDecl);
          SimpleName varDeclName = varDecl.getName();
          String varName = varDeclName.getFullyQualifiedName();

          String pathVariableName = varName;
          StringLiteral pathVariableLiteral = null;

          for (Annotation annotation : annotations) {
            if (annotation instanceof SingleMemberAnnotation) {
              Expression value = ((SingleMemberAnnotation) annotation).getValue();
              if (value instanceof StringLiteral) {
                pathVariableLiteral = ((StringLiteral) value);
                pathVariableName = pathVariableLiteral.getLiteralValue();
                break;
              }
            }
          }

          if (varName.equals(pathVariableName)) {
            hasPathVariable = true;
            this.oldName = varName;
            this.pathVariableLiteral = pathVariableLiteral;

            // find reference in method annotation
            MethodDeclaration methodDecl = (MethodDeclaration) ASTResolving.findAncestor(varDecl,
                ASTNode.METHOD_DECLARATION);
            methodPathVariableSourceRange = new PathVariableSourceRange();
            addPathVariableSourceRanges(methodDecl, pathVariableName, methodPathVariableSourceRange);

            // find reference in type annotation
            TypeDeclaration typeDecl = (TypeDeclaration) ASTResolving.findAncestor(varDecl,
                ASTNode.TYPE_DECLARATION);
            typePathVariableSourceRange = new PathVariableSourceRange();
            addPathVariableSourceRanges(typeDecl, pathVariableName, typePathVariableSourceRange);
          }
        }

      }
      catch (JavaModelException e) {
        StatusHandler.log(e.getStatus());
      }

    }

    return hasPathVariable;
  }

}
TOP

Related Classes of org.springframework.ide.eclipse.quickfix.jdt.RequestMappingRenameParticipant$PathVariableSourceRange

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.