/**
* Copyright (C) 2005 - 2012 Eric Van Dewoestine
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.eclim.plugin.jdt.command.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.eclim.Services;
import org.eclim.annotation.Command;
import org.eclim.command.CommandLine;
import org.eclim.command.Options;
import org.eclim.plugin.jdt.command.impl.ImplCommand;
import org.eclim.plugin.jdt.util.JavaUtils;
import org.eclim.plugin.jdt.util.TypeUtils;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.internal.corext.codemanipulation.AddDelegateMethodsOperation;
import org.eclipse.jdt.internal.corext.codemanipulation.AddDelegateMethodsOperation.DelegateEntry;
import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
/**
* Command to handle creation of delegate methods.
*
* @author Eric Van Dewoestine
*/
@Command(
name = "java_delegate",
options =
"REQUIRED p project ARG," +
"REQUIRED f file ARG," +
"OPTIONAL o offset ARG," +
"OPTIONAL e encoding ARG," +
"OPTIONAL v variable ARG," +
"OPTIONAL s superType ARG," +
"OPTIONAL m methods ARG"
)
public class DelegateCommand
extends ImplCommand
{
private ThreadLocal<IField> field = new ThreadLocal<IField>();
@Override
public Object execute(CommandLine commandLine)
throws Exception
{
String project = commandLine.getValue(Options.PROJECT_OPTION);
String file = commandLine.getValue(Options.FILE_OPTION);
ICompilationUnit src = JavaUtils.getCompilationUnit(project, file);
IJavaElement element = null;
if (commandLine.hasOption(Options.VARIABLE_OPTION)){
String var = commandLine.getValue(Options.VARIABLE_OPTION);
String[] parts = StringUtils.split(var, ".");
String varName = parts[parts.length - 1];
IType type = getType(src, commandLine);
element = type.getField(varName);
}else{
element = src.getElementAt(getOffset(commandLine));
}
if(element == null || element.getElementType() != IJavaElement.FIELD){
return Services.getMessage("not.a.field");
}
IField field = (IField)element;
String signature = field.getTypeSignature();
IType delegateType = TypeUtils.findUnqualifiedType(
src, Signature.getSignatureSimpleName(signature));
if(delegateType == null){
return Services.getMessage("type.not.found",
src.getJavaProject().getElementName(),
Signature.getSignatureSimpleName(signature)) + " " +
Services.getMessage("check.import");
}
this.field.set(field);
return super.execute(commandLine);
}
@Override
protected IType getType(ICompilationUnit src, CommandLine commandLine)
throws Exception
{
if (commandLine.hasOption(Options.VARIABLE_OPTION)){
String var = commandLine.getValue(Options.VARIABLE_OPTION);
String[] parts = StringUtils.split(var, ".");
String typeName = StringUtils.join(parts, '.', 0, parts.length - 1);
return src.getJavaProject().findType(typeName.replace('$', '.'));
}
return super.getType(src, commandLine);
}
@Override
protected IWorkspaceRunnable getImplOperation(
ICompilationUnit src,
IType type,
Set<String> chosen,
IJavaElement sibling,
int pos,
CommandLine commandLine)
throws Exception
{
RefactoringASTParser parser =
new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL);
CompilationUnit cu = parser.parse(type.getCompilationUnit(), true);
ITypeBinding typeBinding = ASTNodes.getTypeBinding(cu, type);
String superType = commandLine.getValue(Options.SUPERTYPE_OPTION);
List<DelegateEntry> delegatable = getDelegatableMethods(cu, typeBinding);
List<DelegateEntry> delegate = new ArrayList<DelegateEntry>();
for (DelegateEntry entry : delegatable){
ITypeBinding declBinding = entry.delegateMethod.getDeclaringClass();
String fqn = declBinding.getQualifiedName().replaceAll("<.*?>", "");
if (fqn.equals(superType) && isChosen(chosen, entry.delegateMethod)){
delegate.add(entry);
}
}
if (delegate.size() > 0){
CodeGenerationSettings settings =
JavaPreferencesSettings.getCodeGenerationSettings(src.getJavaProject());
settings.createComments = true;
return new AddDelegateMethodsOperation(
cu, delegate.toArray(new DelegateEntry[delegate.size()]),
sibling, settings, true, true);
}
return null;
}
@Override
protected ImplResult getImplResult(ICompilationUnit src, IType type)
throws Exception
{
List<DelegateEntry> delegatable = getDelegatableMethods(src, type);
List<IMethodBinding> methods =
new ArrayList<IMethodBinding>(delegatable.size());
for (DelegateEntry entry : delegatable){
methods.add(entry.delegateMethod);
}
String name = type.getFullyQualifiedName() + '.' + field.get().getElementName();
return getImplResult(name, methods);
}
private List<DelegateEntry> getDelegatableMethods(
ICompilationUnit src, IType type)
throws Exception
{
RefactoringASTParser parser =
new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL);
CompilationUnit cu = parser.parse(type.getCompilationUnit(), true);
ITypeBinding typeBinding = ASTNodes.getTypeBinding(cu, type);
return getDelegatableMethods(cu, typeBinding);
}
private List<DelegateEntry> getDelegatableMethods(
CompilationUnit cu, ITypeBinding typeBinding)
throws Exception
{
IVariableBinding variable = ASTNodeSearchUtil
.getFieldDeclarationFragmentNode(field.get(), cu).resolveBinding();
DelegateEntry[] entries =
StubUtility2.getDelegatableMethods(typeBinding);
ArrayList<DelegateEntry> delegatable = new ArrayList<DelegateEntry>();
for (DelegateEntry entry : entries) {
if (entry.field.equals(variable)){
delegatable.add(entry);
}
}
return delegatable;
}
}