blob: 4b95453bc9500bbf20a619921c556f15d33db3a7 [file] [log] [blame]
/**********************************************************************
* This file is part of "Object Teams Development Tooling"-Software
*
* Copyright 2005, 2007 Fraunhofer Gesellschaft, Munich, Germany,
* for its Fraunhofer Institute for Computer Architecture and Software
* Technology (FIRST), Berlin, Germany and Technical University Berlin,
* Germany.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Please visit http://www.eclipse.org/objectteams for updates and contact.
*
* Contributors:
* Fraunhofer FIRST - Initial API and implementation
* Technical University Berlin - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otdt.internal.ui.bindingeditor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.CallinMappingDeclaration;
import org.eclipse.jdt.core.dom.CalloutMappingDeclaration;
import org.eclipse.jdt.core.dom.FieldAccessSpec;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodMappingElement;
import org.eclipse.jdt.core.dom.MethodSpec;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.RoleTypeDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.rewrite.ASTNodeCreator;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.SourceMethod;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.viewsupport.JavaUILabelProvider;
import org.eclipse.jdt.internal.ui.viewsupport.TreeHierarchyLayoutProblemsDecorator;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.objectteams.otdt.core.IMethodMapping;
import org.eclipse.objectteams.otdt.core.IMethodSpec;
import org.eclipse.objectteams.otdt.core.IOTType;
import org.eclipse.objectteams.otdt.core.IRoleType;
import org.eclipse.objectteams.otdt.core.OTModelManager;
import org.eclipse.objectteams.otdt.core.TypeHelper;
import org.eclipse.objectteams.otdt.ui.ImageConstants;
import org.eclipse.objectteams.otdt.ui.OTDTUIPlugin;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
/**
* Select role-Method, callout or callin-kind and base-Method for creation of Callin-/CalloutMappingDeclaration.
*
* @author jwloka
*/
public class BindingConfiguration extends Composite
{
private static final int DESELECT_DISABLE_BUTTONS = 1;
private static final int SELECT_BUTTONS = 0;
private static final String OT_GENERATED_INDICATOR = "_OT$"; //$NON-NLS-1$
private static final String FAKED_METHOD_NAME = '\''+Messages.BindingConfiguration_new_method_label;
private static final Object[] EMPTY_LIST = new Object[0];
private static final String[] NO_STRINGS = new String[0];
private static final int OT_CALLOUT = 0x1000000;
private static final int OT_CALLOUT_OVERRIDE = 0x2000000;
private IMethod[] _roleMethods;
private IMember[] _baseMethods;
private IMethod _fakedMeth;
final TableViewer _roleMethListViewer;
final TableViewer _baseMethListViewer;
final RadioButtonComposite _methMapBtnComp;
private Button _calloutBtn;
private Button _calloutOverrideBtn;
private Button _callinBeforeBtn;
private Button _callinReplaceBtn;
private Button _callinAfterBtn;
private RoleTypeDeclaration _selectedRole;
private CalloutMappingDeclaration _selectedCalloutDecl;
private CalloutMappingDeclaration[] _calloutMappings;
private CallinMappingDeclaration _selectedCallinDecl;
private CallinMappingDeclaration _callinMapping;
private BindingEditor _bindingEditor;
private Button _applyBtn;
private boolean _newCallout;
private List _parameterMappings;
private IType _curTeam;
class BaseMethodContentProvider implements IStructuredContentProvider
{
public Object[] getElements(Object inputElement)
{
return (_baseMethods != null) ? getFilteredMethods() : EMPTY_LIST;
}
public void dispose() {}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
private Object[] getFilteredMethods()
{
List<IMember> result = new ArrayList<IMember>();
for (int idx = 0; idx < _baseMethods.length; idx++)
{
IMember curElem = _baseMethods[idx];
try {
if ( !curElem.getElementName().startsWith(OT_GENERATED_INDICATOR)
&& (!curElem.exists() || !Flags.isSynthetic(curElem.getFlags()))) // methods representing callout don't exist and can't answer getFlags()
{
result.add(curElem);
}
} catch (JavaModelException jme) {
// nop
}
}
return result.toArray();
}
}
class RoleMethodContentProvider implements IStructuredContentProvider
{
public Object[] getElements(Object inputElement)
{
return getFakedMethodList();
}
private Object[] getFakedMethodList()
{
if (_curTeam == null)
{
return EMPTY_LIST;
}
_fakedMeth = _curTeam.getMethod(FAKED_METHOD_NAME, new String[0] );
if (_roleMethods == null)
{
return new IMethod[] { _fakedMeth };
}
else
{
List<IMethod> result = new ArrayList<IMethod>();
for (int idx = 0; idx < _roleMethods.length; idx++)
{
IMethod curElem = _roleMethods[idx];
if (!curElem.getElementName().startsWith(OT_GENERATED_INDICATOR))
{
result.add(curElem);
}
}
result.add(_fakedMeth);
return result.toArray();
}
}
public void dispose() {}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
}
public BindingConfiguration(Composite parent, int style)
{
super(parent, style);
setLayout(new FormLayout());
_bindingEditor = (BindingEditor)parent.getParent();
JavaUILabelProvider labelProvider = new JavaUILabelProvider() {
@Override
public Image getImage(Object element) {
if (element instanceof IMethod) {
// the FAKED_METHOD ('New method) get's a special image:
if (((IMethod)element).getElementName().equals(FAKED_METHOD_NAME))
return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_ADD);
// other methods that don't exist() are assumed to represent a short-hand callout:
if (!((IMethod)element).exists())
return OTDTUIPlugin.getDefault().getImageRegistry().get(ImageConstants.CALLOUTBINDING_IMG);
}
return super.getImage(element);
}
};
labelProvider.addLabelDecorator(new TreeHierarchyLayoutProblemsDecorator());
labelProvider.setTextFlags(JavaElementLabels.M_APP_RETURNTYPE | JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.M_PARAMETER_NAMES);
final Composite composite = new Composite(this, SWT.NONE);
final FormData formData_10 = new FormData();
formData_10.bottom = new FormAttachment(100, -5);
formData_10.right = new FormAttachment(100, -5);
formData_10.top = new FormAttachment(100, -50);
formData_10.left = new FormAttachment(0, 5);
composite.setLayoutData(formData_10);
composite.setLayout(new FormLayout());
_applyBtn = new Button(composite, SWT.NONE);
final FormData formData_11 = new FormData();
formData_11.bottom = new FormAttachment(100, -5);
formData_11.right = new FormAttachment(100, -5);
_applyBtn.setLayoutData(formData_11);
_applyBtn.setText(Messages.BindingConfiguration_apply_button);
_applyBtn.setEnabled(false);
addApplyButtonListener(_applyBtn);
// method mapping button group
_methMapBtnComp = new RadioButtonComposite(this, SWT.NONE);
final FormData formData_1 = new FormData();
formData_1.right = new FormAttachment(60, -5);
formData_1.bottom = new FormAttachment(composite, 5, SWT.TOP);
formData_1.top = new FormAttachment(0, 8);
formData_1.left = new FormAttachment(40, 5);
_methMapBtnComp.setLayoutData(formData_1);
_methMapBtnComp.setLayout(new FormLayout());
_calloutBtn = new Button(_methMapBtnComp, SWT.TOGGLE);
addButtonListener(_calloutBtn);
final FormData formData_3 = new FormData();
formData_3.right = new FormAttachment(100, -5);
formData_3.top = new FormAttachment(0, 5);
formData_3.left = new FormAttachment(0, 5);
_calloutBtn.setLayoutData(formData_3);
_calloutBtn.setText("->"); //$NON-NLS-1$
_calloutOverrideBtn = new Button(_methMapBtnComp, SWT.TOGGLE);
addButtonListener( _calloutOverrideBtn);
final FormData formData_4 = new FormData();
formData_4.right = new FormAttachment(100, -5);
formData_4.top = new FormAttachment(_calloutBtn, 5, SWT.BOTTOM);
formData_4.left = new FormAttachment(0, 5);
_calloutOverrideBtn.setLayoutData(formData_4);
_calloutOverrideBtn.setText("=>"); //$NON-NLS-1$
_callinBeforeBtn = new Button(_methMapBtnComp, SWT.TOGGLE);
addButtonListener(_callinBeforeBtn);
final FormData formData_5 = new FormData();
formData_5.right = new FormAttachment(100, -5);
formData_5.top = new FormAttachment(_calloutOverrideBtn, 5, SWT.BOTTOM);
formData_5.left = new FormAttachment(0, 5);
_callinBeforeBtn.setLayoutData(formData_5);
_callinBeforeBtn.setText("<- before"); //$NON-NLS-1$
_callinReplaceBtn = new Button(_methMapBtnComp, SWT.TOGGLE);
addButtonListener(_callinReplaceBtn);
final FormData formData_6 = new FormData();
formData_6.right = new FormAttachment(100, -5);
formData_6.top = new FormAttachment(_callinBeforeBtn, 5, SWT.BOTTOM);
formData_6.left = new FormAttachment(0, 5);
_callinReplaceBtn.setLayoutData(formData_6);
_callinReplaceBtn.setText("<- replace"); //$NON-NLS-1$
_callinAfterBtn = new Button(_methMapBtnComp, SWT.TOGGLE);
addButtonListener(_callinAfterBtn);
final FormData formData_7 = new FormData();
formData_7.right = new FormAttachment(100, -5);
formData_7.top = new FormAttachment(_callinReplaceBtn, 5, SWT.BOTTOM);
formData_7.left = new FormAttachment(0, 5);
_callinAfterBtn.setLayoutData(formData_7);
_callinAfterBtn.setText("<- after"); //$NON-NLS-1$
final Label roleMethLabel = new Label(this, SWT.NONE);
final FormData formData = new FormData();
formData.right = new FormAttachment(0, 210);
formData.top = new FormAttachment(0, 5);
formData.left = new FormAttachment(0, 5);
roleMethLabel.setLayoutData(formData);
roleMethLabel.setText(Messages.BindingConfiguration_role_methods_label);
_roleMethListViewer = new TableViewer(this, SWT.V_SCROLL | SWT.BORDER | SWT.H_SCROLL);
_roleMethListViewer.setContentProvider(new RoleMethodContentProvider());
_roleMethListViewer.setLabelProvider(labelProvider);
final Table roleMethList = _roleMethListViewer.getTable();
final FormData formData_8 = new FormData();
formData_8.bottom = new FormAttachment(composite, 5, SWT.TOP);
formData_8.right = new FormAttachment(40, 0);
formData_8.top = new FormAttachment(roleMethLabel, 5, SWT.BOTTOM);
formData_8.left = new FormAttachment(0, 5);
roleMethList.setLayoutData(formData_8);
_roleMethListViewer.setSorter(new ViewerSorter());
_roleMethListViewer.setInput(new Object());
addRoleListSelectionChangedListener(_roleMethListViewer);
final Label baseMethLabel = new Label(this, SWT.NONE);
final FormData formData_2 = new FormData();
formData_2.right = new FormAttachment(100, -5);
formData_2.top = new FormAttachment(0, 5);
formData_2.left = new FormAttachment(_methMapBtnComp, 5, SWT.RIGHT);
baseMethLabel.setLayoutData(formData_2);
baseMethLabel.setText(Messages.BindingConfiguration_base_methods_label);
_baseMethListViewer = new TableViewer(this, SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.H_SCROLL);
_baseMethListViewer.setContentProvider(new BaseMethodContentProvider());
_baseMethListViewer.setLabelProvider(labelProvider);
final Table baseMethList = _baseMethListViewer.getTable();
final FormData formData_12 = new FormData();
formData_12.bottom = new FormAttachment(composite, 5, SWT.TOP);
formData_12.right = new FormAttachment(100, -5);
formData_12.top = new FormAttachment(baseMethLabel, 5, SWT.BOTTOM);
formData_12.left = new FormAttachment(60, 0);
baseMethList.setLayoutData(formData_12);
_baseMethListViewer.setSorter(new ViewerSorter());
_baseMethListViewer.setInput(new Object());
addBaseListSelectionChangedListener(_baseMethListViewer);
}
private void addRoleListSelectionChangedListener(final TableViewer tableViewer)
{
ISelectionChangedListener listener = new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
if (validateSelections())
{
_methMapBtnComp.enableAll();
}
toggleApplyButton();
}
};
tableViewer.addSelectionChangedListener(listener);
}
private void addBaseListSelectionChangedListener(final TableViewer tableViewer)
{
ISelectionChangedListener listener = new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
if (!validateSelections())
{
return;
}
//no abstract methods selected
_methMapBtnComp.enableAll();
if (!tableViewer.getSelection().isEmpty()
&& tableViewer.getTable().getSelection().length > 1)
{
toggleModifierButtons(OT_CALLOUT|OT_CALLOUT_OVERRIDE, DESELECT_DISABLE_BUTTONS);
_methMapBtnComp.removeSelectionButton(_calloutBtn);
_methMapBtnComp.removeSelectionButton(_calloutOverrideBtn);
}
toggleApplyButton();
}
};
tableViewer.addSelectionChangedListener(listener);
}
private boolean validateSelections()
{
StructuredSelection selectedBaseIMembers = (StructuredSelection)_baseMethListViewer.getSelection();
for (Iterator iter = selectedBaseIMembers.iterator(); iter.hasNext();)
{
IMember baseIMember = (IMember) iter.next();
try
{
if (Flags.isAbstract(baseIMember.getFlags()))
{
_methMapBtnComp.deselectAll();
_methMapBtnComp.disableAll();
toggleApplyButton();
return false;
}
}
catch (JavaModelException ex)
{
return false;
}
}
StructuredSelection selectedRoleIMethod = (StructuredSelection)_roleMethListViewer.getSelection();
if (selectedRoleIMethod.isEmpty())
{
return true;
}
IMethod roleMethod = (IMethod)selectedRoleIMethod.getFirstElement();
try
{
if (roleMethod.getElementName().equals(FAKED_METHOD_NAME))
{
toggleModifierButtons(OT_CALLOUT_OVERRIDE|
Modifier.OT_AFTER_CALLIN|
Modifier.OT_BEFORE_CALLIN|
Modifier.OT_REPLACE_CALLIN,
DESELECT_DISABLE_BUTTONS);
toggleApplyButton();
return false;
}
if (!roleMethod.getElementName().equals(FAKED_METHOD_NAME)
&& !Flags.isCallin(roleMethod.getFlags())
&& !Flags.isAbstract(roleMethod.getFlags()))
{
toggleModifierButtons(Modifier.OT_REPLACE_CALLIN|OT_CALLOUT, DESELECT_DISABLE_BUTTONS);
toggleApplyButton();
return false;
}
if (!roleMethod.getElementName().equals(FAKED_METHOD_NAME)
&& Flags.isCallin(roleMethod.getFlags())
&& !Flags.isAbstract(roleMethod.getFlags()))
{
toggleModifierButtons(OT_CALLOUT_OVERRIDE|
OT_CALLOUT|
Modifier.OT_AFTER_CALLIN|
Modifier.OT_BEFORE_CALLIN,
DESELECT_DISABLE_BUTTONS);
toggleApplyButton();
return false;
}
}
catch (JavaModelException ex)
{
return false;
}
return true;
}
protected void checkSubclass() {}
public IMember[] getBaseMethods(IType baseClass) throws JavaModelException
{
List<IMember> result = new ArrayList<IMember>();
//FIXME: cleaner but way(!) too slow:
//TypeHelper.getInheritedMethods(baseClass, true, false, false, new NullProgressMonitor());//
// ---------- stolen (and adapted) from CallinMapping.findBaseMethods():
IType[] typeParents = TypeHelper.getSuperTypes(baseClass);
if (OTModelManager.hasOTElementFor(baseClass)) {
IOTType otType = OTModelManager.getOTElement(baseClass);
if (otType.isRole()) {
IType[] implicitSupers = TypeHelper.getImplicitSuperTypes((IRoleType)otType);
int len1 = implicitSupers.length;
int len2 = typeParents.length;
// shift to back:
System.arraycopy(
typeParents, 0,
typeParents = new IType[len1+len2-1],
len1-1, // let tsupers overwrite first element which repeats the original baseClass
len2);
// insert at front (implicit has higher priority)
System.arraycopy(
implicitSupers, 0,
typeParents, 0,
len1);
}
}
HashSet<String> signatures = new HashSet<String>(); // for filtering of duplicates.
for (int i = 0; i < typeParents.length; i++) {
if (typeParents[i].getFullyQualifiedName().equals(TypeHelper.JAVA_LANG_OBJECT))
continue;
// TODO(SH): don't include private fields from super classes
IField[] fields = typeParents[i].getFields();
for (int fieldIdx = 0; fieldIdx < fields.length; fieldIdx++)
{
IField field = fields[fieldIdx];
String signature = field.getElementName()+field.getTypeSignature();
if (!signatures.contains(signature))
{
result.add(field);
signatures.add(signature);
}
}
IMethod[] methods = typeParents[i].getMethods();
for (int methIdx = 0; methIdx < methods.length; methIdx++)
{
IMethod method = methods[methIdx];
String signature = method.getElementName()+method.getSignature();
if ( !method.isConstructor()
&& !signatures.contains(signature))
{
result.add(method);
signatures.add(signature);
}
}
IOTType otType = OTModelManager.getOTElement(typeParents[i]);
if (otType != null && otType.isRole()) {
// add short-hand callout methods:
IMethodMapping[] mappings = ((IRoleType)otType).getMethodMappings(IRoleType.CALLOUTS);
for (int j = 0; j < mappings.length; j++) {
IMethodSpec method = mappings[j].getRoleMethodHandle();
String signature = method.getSelector()+method.getSignature();
if (!signatures.contains(signature))
{
result.add(SourceMethod.createHandle((JavaElement)typeParents[i], method));
signatures.add(signature);
}
}
}
}
// -----------
return result.toArray(new IMember[result.size()]);
}
public void setFocusRole(RoleTypeDeclaration focusRole, IType teamType, boolean initial)
{
if (initial)
{
_selectedCallinDecl = null;
_selectedCalloutDecl = null;
_parameterMappings = null;
}
_selectedRole = focusRole;
IJavaProject project = teamType.getCompilationUnit().getJavaProject();
IType teamClass = null;
// implicit inherited role class methods
try
{
teamClass = project.findType(teamType.getFullyQualifiedName('.'));
_roleMethods = TypeHelper.getAllRoleMethods(
teamClass,
focusRole.getName().toString());
}
catch (JavaModelException ex)
{
openErrorDialog(Messages.BindingConfiguration_error_retrieving_role_methods);
}
Type baseType = focusRole.getBaseClassType();
// base class methods
if (baseType != null)
{
try
{
String qualifiedBaseName = null;
if (baseType instanceof SimpleType) {
// try for cached names (those roles created within the binding editor):
Name baseName = ((SimpleType)baseType).getName();
qualifiedBaseName = (baseName instanceof QualifiedName) ?
baseName.getFullyQualifiedName() :
this._bindingEditor._baseClassLookup.get(((SimpleName)baseName).getIdentifier());
}
if (qualifiedBaseName == null) // other roles should be resolvable:
qualifiedBaseName = focusRole.resolveBinding().getBaseClass().getQualifiedName();
if (qualifiedBaseName != null)
_baseMethods = getBaseMethods(project.findType(qualifiedBaseName));
else
OTDTUIPlugin.logException("Failed to resolve focus role - no methods available.", null); //$NON-NLS-1$
}
catch (JavaModelException ex)
{
OTDTUIPlugin.logException(ex.getMessage(), ex);
}
}
// clear selection
_roleMethListViewer.setSelection(new StructuredSelection(EMPTY_LIST));
_baseMethListViewer.setSelection(new StructuredSelection(EMPTY_LIST));
_roleMethListViewer.refresh();
_baseMethListViewer.refresh();
_methMapBtnComp.enableAll();
_methMapBtnComp.deselectAll();
toggleApplyButton();
}
IType findRoleType (IType teamClass, String roleName)
throws JavaModelException
{
IType[] roles = teamClass.getTypes();
for (IType roleType : roles)
if (roleType.getElementName().equals(roleName))
return roleType;
for (IType roleType : roles)
{
IType result = findRoleType(roleType, roleName);
if (result != null)
return result;
}
return null;
}
private void toggleApplyButton()
{
if (_baseMethListViewer.getSelection().isEmpty()
|| _roleMethListViewer.getSelection().isEmpty()
|| (_methMapBtnComp.getSelectedButton() == null))
{
_applyBtn.setEnabled(false);
}
else
{
_applyBtn.setEnabled(true);
}
}
public void setCalloutMapping(ASTNode selectedNode, IType teamType)
{
if ( !(selectedNode instanceof CalloutMappingDeclaration) )
{
return;
}
_selectedCallinDecl = null;
_selectedCalloutDecl = (CalloutMappingDeclaration)selectedNode;
RoleTypeDeclaration roleTypeDecl = (RoleTypeDeclaration)_selectedCalloutDecl.getParent();
setFocusRole(roleTypeDecl, teamType, false);
MethodSpec roleMethSpec = (MethodSpec)_selectedCalloutDecl.getRoleMappingElement();
IMember roleMeth = findCorrespondingIMember(roleMethSpec, _roleMethods, null);
if (roleMeth != null)
{
_roleMethListViewer.setSelection( new StructuredSelection(roleMeth) );
}
else
{
_roleMethListViewer.setSelection( new StructuredSelection(_fakedMeth) );
}
MethodMappingElement baseSpec = (MethodMappingElement)_selectedCalloutDecl.getBaseMappingElement();
List<MethodMappingElement> baseSpecs = new ArrayList<MethodMappingElement>();
baseSpecs.add(baseSpec);
List<IMember> curBaseMeths = findCorrespondingIMembers(baseSpecs, _baseMethods);
if (curBaseMeths != null)
{
_baseMethListViewer.setSelection( new StructuredSelection(curBaseMeths) );
}
else
{
_baseMethListViewer.setSelection( new StructuredSelection(EMPTY_LIST) );
}
_parameterMappings = _selectedCalloutDecl.getParameterMappings();
if( _selectedCalloutDecl.isCalloutOverride())
{
_methMapBtnComp.setSelectionButton(_calloutOverrideBtn);
}
else
{
_methMapBtnComp.setSelectionButton(_calloutBtn);
}
toggleApplyButton();
}
public void setCallinMapping(ASTNode selectedNode, IType teamType)
{
if ( !(selectedNode instanceof CallinMappingDeclaration))
{
return;
}
_selectedCalloutDecl = null;
_selectedCallinDecl = (CallinMappingDeclaration)selectedNode;
RoleTypeDeclaration roleTypeDecl = (RoleTypeDeclaration)_selectedCallinDecl.getParent();
setFocusRole(roleTypeDecl, teamType, false);
MethodSpec roleMethSpec = (MethodSpec)_selectedCallinDecl.getRoleMappingElement();
IMember roleMeth = findCorrespondingIMember(roleMethSpec, _roleMethods, null);
if (roleMeth != null)
{
_roleMethListViewer.setSelection( new StructuredSelection(roleMeth) );
}
else
{
_roleMethListViewer.setSelection( new StructuredSelection(EMPTY_LIST) );
}
java.util.List<MethodMappingElement> baseMapElems = _selectedCallinDecl.getBaseMappingElements();
if (baseMapElems.size() == 0)
{
return;
}
java.util.List<IMember> baseMembs = findCorrespondingIMembers(baseMapElems, _baseMethods);
if (baseMembs != null)
{
_baseMethListViewer.setSelection( new StructuredSelection(baseMembs) );
}
else
{
_baseMethListViewer.setSelection( new StructuredSelection(EMPTY_LIST) );
}
_parameterMappings = _selectedCallinDecl.getParameterMappings();
toggleModifierButtons(_selectedCallinDecl.getCallinModifier(), SELECT_BUTTONS);
toggleApplyButton();
}
private List<IMember> findCorrespondingIMembers(List<MethodMappingElement> methodSpecs, IMember[] members)
{
Hashtable<String, Integer> methodAppearances = getMethodAppearances(members);
List<IMember> baseMembers = new ArrayList<IMember>();
for (Iterator<MethodMappingElement> iter = methodSpecs.iterator(); iter.hasNext();)
{
MethodMappingElement methodSpec = iter.next();
IMember foundMethod = findCorrespondingIMember(methodSpec, members, methodAppearances);
baseMembers.add(foundMethod);
}
return baseMembers;
}
private IMember findCorrespondingIMember(MethodMappingElement methodSpec, IMember[] methods, Hashtable<String, Integer> methodAppearances)
{
if (methodAppearances == null)
methodAppearances = getMethodAppearances(methods);
String methodName = methodSpec.getName().toString();
for (int idx = 0; idx < methods.length; idx++)
{
if (methodName.equals(methods[idx].getElementName()))
{
Integer value = methodAppearances.get(methodName);
if (value.intValue() > 1)
{
// FIXME(SH): handle field cases:
if ( methodSpec instanceof MethodSpec
&& methods[idx] instanceof IMethod)
{
List parameters = ((MethodSpec)methodSpec).parameters();
String []parameterTypes = ((IMethod)methods[idx]).getParameterTypes();
if (parameters.size() != parameterTypes.length)
{
continue;
}
if (validateParameterMatching(parameters, parameterTypes))
{
return methods[idx];
}
}
}
else
{
return methods[idx];
}
}
}
return null;
}
private boolean validateParameterMatching(List parameters, String[] parameterTypes)
{
boolean totallyMatch = true;
int counter = 0;
for (Iterator iter = parameters.iterator(); iter.hasNext();)
{
SingleVariableDeclaration variable = (SingleVariableDeclaration) iter .next();
String paramTypeNameFromMethodSpec = null;
if (variable.getType().isPrimitiveType())
{
paramTypeNameFromMethodSpec = ((PrimitiveType)variable.getType()).getPrimitiveTypeCode().toString();
}
if (variable.getType().isSimpleType())
{
ITypeBinding typeBinding =((SimpleType)variable.getType()).resolveBinding();
if (typeBinding == null)
{
paramTypeNameFromMethodSpec = ((SimpleType)variable.getType()).getName().getFullyQualifiedName();
}
else
{
paramTypeNameFromMethodSpec = typeBinding.getQualifiedName();
}
}
if (variable.getType().isArrayType())
{
Type arrayType = ((ArrayType)variable.getType()).getElementType();
if (arrayType.isPrimitiveType())
{
paramTypeNameFromMethodSpec = ((PrimitiveType)arrayType).getPrimitiveTypeCode().toString();
}
if (arrayType.isSimpleType())
{
ITypeBinding typeBinding =((SimpleType)arrayType).resolveBinding();
if (typeBinding == null)
{
paramTypeNameFromMethodSpec = ((SimpleType)arrayType).getName().getFullyQualifiedName();
}
else
{
paramTypeNameFromMethodSpec = typeBinding.getQualifiedName();
}
}
int dimensions = ((ArrayType)variable.getType()).getDimensions();
for (int i = 0; i < dimensions; i++) {
paramTypeNameFromMethodSpec += "[]"; //$NON-NLS-1$
}
}
//TODO(ike): Find a way to resolved parameters of methodSpecs to get fully qualified names
String paramTypeNameFromIMethod = Signature.toString(parameterTypes[counter]);
String simpleTypeName = getSimpleParameterName(paramTypeNameFromIMethod);
if (!simpleTypeName.equals(paramTypeNameFromMethodSpec))
{
totallyMatch = false;
}
counter++;
}
return totallyMatch;
}
private String getSimpleParameterName(String parameterName)
{
String [] simpleNameArray = parameterName.split("\\."); //$NON-NLS-1$
if (simpleNameArray.length == 0)
return parameterName;
else
return simpleNameArray[simpleNameArray.length - 1];
}
private Hashtable<String, Integer> getMethodAppearances(IMember[] methods)
{
Hashtable<String, Integer> appearances = new Hashtable<String, Integer>();
for (int idx = 0; idx < methods.length; idx++)
{
String methodName = methods[idx].getElementName();
if (appearances.containsKey(methodName))
{
Integer value = appearances.get(methodName);
int app = value.intValue();
app++;
appearances.put(methodName, new Integer(app));
}
else
{
appearances.put(methodName, new Integer(1));
}
}
return appearances;
}
private void toggleModifierButtons(int modifiers, int selectionLevel)
{
List<Button> buttonList = getButtonsForModifiers(modifiers);
switch (selectionLevel)
{
case SELECT_BUTTONS:
for (Iterator<Button> iter = buttonList.iterator(); iter.hasNext();)
{
Button button = iter.next();
_methMapBtnComp.setSelectionButton(button);
}
break;
case DESELECT_DISABLE_BUTTONS:
if (Modifier.isReplace(modifiers))
{
_callinReplaceBtn.setEnabled(false);
_methMapBtnComp.removeSelectionButton(_callinReplaceBtn);
}
else
{
_callinReplaceBtn.setEnabled(true);
}
if (Modifier.isBefore(modifiers))
{
_callinBeforeBtn.setEnabled(false);
_methMapBtnComp.removeSelectionButton(_callinBeforeBtn);
}
else
{
_callinBeforeBtn.setEnabled(true);
}
if (Modifier.isAfter(modifiers))
{
_callinAfterBtn.setEnabled(false);
_methMapBtnComp.removeSelectionButton(_callinAfterBtn);
}
else
{
_callinAfterBtn.setEnabled(true);
}
if (isCallout(modifiers))
{
_calloutBtn.setEnabled(false);
_methMapBtnComp.removeSelectionButton(_calloutBtn);
}
else
{
_calloutBtn.setEnabled(true);
}
if (isCalloutOverride(modifiers))
{
_calloutOverrideBtn.setEnabled(false);
_methMapBtnComp.removeSelectionButton(_calloutOverrideBtn);
}
else
{
_calloutOverrideBtn.setEnabled(true);
}
break;
default:
break;
}
}
private List<Button> getButtonsForModifiers(int modifiers)
{
List<Button> buttonList = new ArrayList<Button>();
if (Modifier.isReplace(modifiers))
buttonList.add(_callinReplaceBtn);
if (Modifier.isBefore(modifiers))
buttonList.add(_callinBeforeBtn);
if (Modifier.isAfter(modifiers))
buttonList.add(_callinAfterBtn);
if (isCallout(modifiers))
buttonList.add(_calloutBtn);
if (isCalloutOverride(modifiers))
buttonList.add(_calloutBtn);
return buttonList;
}
private boolean isCalloutOverride(int modifiers)
{
return (modifiers & OT_CALLOUT_OVERRIDE) != 0;
}
private boolean isCallout(int modifiers)
{
return (modifiers & OT_CALLOUT) != 0;
}
private void addButtonListener(Button button)
{
SelectionListener buttonListener = new SelectionListener() {
public void widgetSelected(SelectionEvent evt)
{
Button selectedButton = (Button)evt.getSource();
_methMapBtnComp.doRadioButtonBehavior(selectedButton);
toggleApplyButton();
}
public void widgetDefaultSelected(SelectionEvent evt) {}
};
button.addSelectionListener(buttonListener);
}
private void addApplyButtonListener(Button applyButton)
{
SelectionListener applyButtonListener = new SelectionAdapter()
{
public void widgetSelected(SelectionEvent evt)
{
applyPressed();
}
};
applyButton.addSelectionListener(applyButtonListener);
}
private boolean createMethodMapping()
{
int methMapModifier = 0;
boolean calloutOverride = false;
boolean signatureFlag = true;
_newCallout = true;
Button selectedButton = _methMapBtnComp.getSelectedButton();
if (_calloutBtn.equals(selectedButton))
{
methMapModifier = 0;
_newCallout = true;
}
if (_calloutOverrideBtn.equals(selectedButton))
{
calloutOverride = true;
methMapModifier = 0;
_newCallout = true;
}
if (_callinReplaceBtn.equals(selectedButton))
{
methMapModifier = Modifier.OT_REPLACE_CALLIN;
_newCallout = false;
}
if (_callinBeforeBtn.equals(selectedButton))
{
methMapModifier = Modifier.OT_BEFORE_CALLIN;
_newCallout = false;
}
if (_callinAfterBtn.equals(selectedButton))
{
methMapModifier = Modifier.OT_AFTER_CALLIN;
_newCallout = false;
}
StructuredSelection selectedRoleMethod = (StructuredSelection)_roleMethListViewer.getSelection();
if (selectedRoleMethod.isEmpty())
{
return false;
}
StructuredSelection selectedBaseMethods = (StructuredSelection)_baseMethListViewer.getSelection();
if (selectedBaseMethods.isEmpty())
{
return false;
}
IMethod roleMethod = (IMethod) selectedRoleMethod.getFirstElement();
IMember[] baseMethods = new IMember[selectedBaseMethods.size()];
int baseMethodsCount = 0;
for (Iterator iter = selectedBaseMethods.iterator(); iter.hasNext();)
{
IMember baseMethod = (IMember) iter.next();
baseMethods[baseMethodsCount++] = baseMethod;
}
AST ast = _selectedRole.getAST();
if (_newCallout)
{
if (baseMethods[0] instanceof IField) {
this._calloutMappings = new CalloutMappingDeclaration[] {
createCalloutMapping(ast, roleMethod, baseMethods[0], Modifier.OT_GET_CALLOUT, calloutOverride, signatureFlag),
createCalloutMapping(ast, roleMethod, baseMethods[0], Modifier.OT_SET_CALLOUT, calloutOverride, signatureFlag)};
return this._calloutMappings[0] != null && this._calloutMappings[1] != null;
} else {
this._calloutMappings = new CalloutMappingDeclaration[] {
createCalloutMapping(ast, roleMethod, baseMethods[0], methMapModifier, calloutOverride, signatureFlag)
};
return this._calloutMappings[0] != null;
}
}
else
{
return createCallinMapping(ast, roleMethod, baseMethods, methMapModifier, signatureFlag);
}
}
private boolean createCallinMapping(AST ast, IMethod roleIMethod, IMember[] baseMethods, int modifier, boolean signatureFlag)
{
// can only bind methods in callin:
for (IMember member : baseMethods)
if (!(member instanceof IMethod))
return false;
MethodSpec givenRoleMSpec = null;
List<MethodSpec> givenBaseMSpecs = null;
if (_selectedCallinDecl != null)
{
givenRoleMSpec = (MethodSpec)_selectedCallinDecl.getRoleMappingElement();
givenBaseMSpecs = _selectedCallinDecl.getBaseMappingElements();
}
IMethod templateForRoleMethodSpec = roleIMethod;
if (templateForRoleMethodSpec.getElementName().startsWith(FAKED_METHOD_NAME))
templateForRoleMethodSpec = (IMethod)baseMethods[0]; // use the first base method as template for the role method spec
// FIXME: support automatic creation of a new role method
MethodSpec roleMethodSpec = createMethodSpec(ast, templateForRoleMethodSpec, givenRoleMSpec, signatureFlag);
if (roleMethodSpec == null)
return false;
List<MethodMappingElement> baseMethodSpecs = new ArrayList<MethodMappingElement>();
for (int idx = 0; idx < baseMethods.length; idx++)
{
IMethod baseIMethod = (IMethod)baseMethods[idx];
MethodSpec baseMSpec = null;
if ((givenBaseMSpecs != null) && baseMethods.length == 1)
{
baseMSpec = givenBaseMSpecs.get(idx);
}
MethodMappingElement baseMethodSpec = createMethodSpec(ast, baseIMethod, baseMSpec, signatureFlag);
if (baseMethodSpec!= null)
{
baseMethodSpecs.add(baseMethodSpec);
}
}
if (_selectedCallinDecl == null)
{
_parameterMappings = null;
}
_callinMapping = ASTNodeCreator.createCallinMappingDeclaration(
ast,
null,
modifier,
roleMethodSpec,
baseMethodSpecs,
_parameterMappings);
return true;
}
private CalloutMappingDeclaration createCalloutMapping(
AST ast,
IMethod roleMethod,
IMember baseMember,
int bindingModifier,
boolean calloutOverride,
boolean signatureFlag)
{
MethodSpec selRolMethSpec = null;
MethodMappingElement selBasMethSpec = null;
if (_selectedCalloutDecl != null)
{
selRolMethSpec = (MethodSpec)_selectedCalloutDecl.getRoleMappingElement();
selBasMethSpec = _selectedCalloutDecl.getBaseMappingElement();
if (baseMember instanceof IMethod && !(selBasMethSpec instanceof MethodSpec))
return null; // cannot change from method to field.
if (baseMember instanceof IField && !(selBasMethSpec instanceof FieldAccessSpec))
return null; // cannot change from field to method.
}
MethodMappingElement baseMethodSpec = null;
if (baseMember instanceof IMethod)
baseMethodSpec = createMethodSpec(
ast,
(IMethod)baseMember,
(MethodSpec)selBasMethSpec,
signatureFlag);
else
try {
IField iField = (IField)baseMember;
baseMethodSpec = ASTNodeCreator.createFieldAccSpec(
ast,
(bindingModifier == Modifier.OT_GET_CALLOUT)/*isSetter*/,
iField.getElementName(),
Signature.toString(iField.getTypeSignature()),
signatureFlag
);
} catch (Exception e) {
return null;
}
if (baseMethodSpec == null)
{
return null;
}
MethodMappingElement roleMethodSpec = null;
if (roleMethod.getElementName().startsWith(FAKED_METHOD_NAME))
{
if (baseMember instanceof IMethod)
roleMethodSpec = createMethodSpec(
ast,
(IMethod)baseMember,
null/*givenSpec*/,
signatureFlag);
else
try {
IField baseField = (IField) baseMember;
String name = baseMember.getElementName();
if (name.length() == 1)
name = name.toUpperCase();
else
name = Character.toUpperCase(name.charAt(0))+name.substring(1);
if (bindingModifier == Modifier.OT_GET_CALLOUT)
roleMethodSpec = createMethodSpec(
ast,
baseField.getTypeSignature(),
"get"+name, //$NON-NLS-1$
NO_STRINGS/*parameterTypes*/,
NO_STRINGS/*parameterNames*/,
null/*givenSpec*/,
signatureFlag);
else
roleMethodSpec = createMethodSpec(
ast,
"V", //$NON-NLS-1$
"set"+name, //$NON-NLS-1$
new String[]{baseField.getTypeSignature()},
new String[]{baseMember.getElementName()},
null/*givenSpec*/,
signatureFlag);
} catch (JavaModelException e) {
return null;
}
}
else
{
roleMethodSpec = createMethodSpec(
ast,
roleMethod,
selRolMethSpec,
signatureFlag);
}
if (roleMethodSpec == null)
{
return null;
}
if (_selectedCalloutDecl == null)
{
_parameterMappings = null;
}
return ASTNodeCreator.createCalloutMappingDeclaration(
ast,
null,
0, // modifiers
roleMethodSpec,
baseMethodSpec,
bindingModifier,
_parameterMappings,
calloutOverride,
signatureFlag);
}
private MethodSpec createMethodSpec(AST ast, IMethod baseMember, MethodSpec givenMethodSpec, boolean signatureFlag) {
try {
return createMethodSpec(ast, baseMember.getReturnType(), baseMember.getElementName(), baseMember.getParameterTypes(), baseMember.getParameterNames(), givenMethodSpec, signatureFlag);
} catch (JavaModelException e) {
return null;
}
}
private MethodSpec createMethodSpec(AST ast,
String typeSignature, String name, String[] parameterTypes, String[] parameterNames,
MethodSpec givenMethodSpec, boolean signatureFlag)
{
String returnTypeString = Signature.toString(typeSignature);
Type returnType = ASTNodeCreator.createType(ast, returnTypeString);
List mSpecParameters = null;
if (givenMethodSpec != null)
{
mSpecParameters = givenMethodSpec.parameters();
}
java.util.List<SingleVariableDeclaration> methodParameters = new ArrayList<SingleVariableDeclaration>();
for (int idx = 0; idx < parameterTypes.length; idx++)
{
Type parameterType = ASTNodeCreator.createType(
ast,
Signature.getSimpleName(Signature.toString(parameterTypes[idx])));
SingleVariableDeclaration roleParameter;
if (mSpecParameters != null && mSpecParameters.size()==parameterNames.length)
{
SingleVariableDeclaration param = (SingleVariableDeclaration)mSpecParameters.get(idx);
roleParameter =
ASTNodeCreator.createArgument(ast, 0, parameterType, param.getName().toString(), null);
}
else
{
roleParameter =
ASTNodeCreator.createArgument(ast, 0, parameterType, parameterNames[idx], null);
}
methodParameters.add(roleParameter);
}
MethodSpec methodSpec = ASTNodeCreator.createMethodSpec(
ast,
name,
returnType,
methodParameters,
signatureFlag
);
return methodSpec;
}
//copied from org.soothsayer.util.ASTNodeHelper;
public static String getMethodSignature(IMethod meth)
{
StringBuffer result = new StringBuffer();
if (meth != null)
{
result.append(meth.getElementName());
result.append('(');
String[] parameterTypes = meth.getParameterTypes();
for (int idx = 0; idx < parameterTypes.length; idx++)
{
String curType = parameterTypes[idx];
result.append(curType);
if (idx < parameterTypes.length)
{
result.append(", "); //$NON-NLS-1$
}
}
result.append(')');
}
return result.toString();
}
public void resetLists()
{
_baseMethListViewer.getTable().removeAll();
_roleMethListViewer.getTable().removeAll();
_methMapBtnComp.enableAll();
_methMapBtnComp.deselectAll();
}
public void setCurrentTeamForMethodFake(IType teamType)
{
_curTeam = teamType;
}
private void applyPressed()
{
if (_selectedRole.isRoleFile()) {
openErrorDialog(NLS.bind(
Messages.BindingConfiguration_error_cant_edit_rolefile,
_selectedRole.getName().getIdentifier(),
_selectedRole.getName().getIdentifier()));
return;
}
RoleTypeDeclaration currentRole= _selectedRole;
while (true) {
currentRole= (RoleTypeDeclaration)ASTNodes.getParent(currentRole, ASTNode.ROLE_TYPE_DECLARATION);
if (currentRole == null)
break;
if (currentRole.isRoleFile()) {
if (this._bindingEditor.isRootTeam(currentRole))
break;
openErrorDialog(NLS.bind(
Messages.BindingConfiguration_error_cant_edit_rolefile_nested,
new Object[]{_selectedRole.getName().getIdentifier(),
currentRole.getName().getIdentifier(),
currentRole.getName().getIdentifier()}));
return;
}
currentRole= (RoleTypeDeclaration)ASTNodes.getParent(_selectedRole, ASTNode.ROLE_TYPE_DECLARATION);
}
_calloutMappings = null;
_callinMapping = null;
int selectedIndex = -1;
if (createMethodMapping())
{
if (_calloutMappings != null)
{
if (_selectedCalloutDecl != null)
{
selectedIndex = _selectedRole.bodyDeclarations().indexOf(_selectedCalloutDecl);
_selectedRole.bodyDeclarations().remove(_selectedCalloutDecl);
}
if (_selectedCallinDecl != null)
{
selectedIndex = _selectedRole.bodyDeclarations().indexOf(_selectedCallinDecl);
_selectedRole.bodyDeclarations().remove(_selectedCallinDecl);
}
if (selectedIndex == -1){
_selectedRole.bodyDeclarations().add(_calloutMappings[0]);
if (_calloutMappings.length>1)
_selectedRole.bodyDeclarations().add(_calloutMappings[1]);
}
else
{
_selectedRole.bodyDeclarations().add(selectedIndex, _calloutMappings[0]);
if (_calloutMappings.length>1)
_selectedRole.bodyDeclarations().add(selectedIndex, _calloutMappings[1]);
}
}
if (_callinMapping != null)
{
if (_selectedCallinDecl != null)
{
selectedIndex = _selectedRole.bodyDeclarations().indexOf(_selectedCallinDecl);
_selectedRole.bodyDeclarations().remove(_selectedCallinDecl);
}
if (_selectedCalloutDecl != null)
{
selectedIndex = _selectedRole.bodyDeclarations().indexOf(_selectedCalloutDecl);
_selectedRole.bodyDeclarations().remove(_selectedCalloutDecl);
}
if (selectedIndex == -1)
{
_selectedRole.bodyDeclarations().add(_callinMapping);
}
else
{
_selectedRole.bodyDeclarations().add(selectedIndex, _callinMapping);
}
}
// clear selection
_roleMethListViewer.setSelection(new StructuredSelection(EMPTY_LIST));
_baseMethListViewer.setSelection(new StructuredSelection(EMPTY_LIST));
_roleMethListViewer.refresh();
_baseMethListViewer.refresh();
_bindingEditor.refresh();
if (this._callinMapping != null) {
_bindingEditor.methodBindingAdded(this._callinMapping);
} else {
_bindingEditor.methodBindingAdded(this._calloutMappings[0]);
if (this._calloutMappings.length > 1)
_bindingEditor.methodBindingAdded(this._calloutMappings[1]);
}
}
else
{
openErrorDialog(Messages.BindingConfiguration_error_binding_creation_failed);
_roleMethListViewer.setSelection(new StructuredSelection(EMPTY_LIST));
_baseMethListViewer.setSelection(new StructuredSelection(EMPTY_LIST));
_roleMethListViewer.refresh();
_baseMethListViewer.refresh();
_methMapBtnComp.enableAll();
_methMapBtnComp.deselectAll();
_bindingEditor.refresh();
}
}
private void openErrorDialog(String message)
{
MessageDialog.openError(getShell(), Messages.BindingConfiguration_error_unspecific, message);
}
}