package org.rubypeople.rdt.internal.launching; import org.eclipse.core.expressions.PropertyTester; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.NullProgressMonitor; import org.rubypeople.rdt.core.IMember; import org.rubypeople.rdt.core.IMethod; import org.rubypeople.rdt.core.IRubyElement; import org.rubypeople.rdt.core.IRubyScript; import org.rubypeople.rdt.core.IType; import org.rubypeople.rdt.core.RubyModelException; public class RubyLaunchableTester extends PropertyTester { /** * name for the "has method" property */ private static final String PROPERTY_HAS_METHOD = "hasMethod"; //$NON-NLS-1$ /** * name for the "extends class" property */ private static final String PROPERTY_EXTENDS_CLASS = "extendsClass"; //$NON-NLS-1$ /** * "is container" property */ private static final String PROPERTY_IS_CONTAINER = "isContainer"; //$NON-NLS-1$ /** * name for the PROPERTY_PROJECT_NATURE property */ private static final String PROPERTY_PROJECT_NATURE = "hasProjectNature"; //$NON-NLS-1$ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { if (PROPERTY_IS_CONTAINER.equals(property)) { if (receiver instanceof IAdaptable) { IResource resource = (IResource)((IAdaptable)receiver).getAdapter(IResource.class); if (resource != null) { return resource instanceof IContainer; } } return false; } if(PROPERTY_PROJECT_NATURE.equals(property)) { if (receiver instanceof IAdaptable) { IResource resource = (IResource)((IAdaptable)receiver).getAdapter(IResource.class); if (resource != null) { return hasProjectNature(resource, (String)args[0]); } } } IRubyElement element = null; if (receiver instanceof IAdaptable) { element = (IRubyElement) ((IAdaptable)receiver).getAdapter(IRubyElement.class); if(element != null) { if(!element.exists()) { return false; } } } if (PROPERTY_HAS_METHOD.equals(property)) { return hasMethod(element, args); } if(PROPERTY_EXTENDS_CLASS.equals(property)) { return hasSuperclass(element, (String)args[0]); } if(PROPERTY_PROJECT_NATURE.equals(property)) { return hasProjectNature(element, (String)args[0]); } return false; } private boolean hasProjectNature(IResource resource, String ntype) { try { if(resource != null) { IProject proj = resource.getProject(); return proj.isAccessible() && proj.hasNature(ntype); } } catch (CoreException e) {} return false; } /** * Determines is the ruby element contains a specific method. * <p> * The syntax for the property tester is of the form: methodname, * signature, modifiers. * </p> * <ol> * <li>methodname - case sensitive method name, required. For example, * <code>toString</code>.</li> * <li>signature - JLS style method signature, required. For example, * <code>(QString;)V</code>.</li> * <li>modifiers - optional space seperated list of modifiers, for * example, <code>public static</code>.</li> * </ol> * @param element the element to check for the method * @param args first arg is method name, secondary args are parameter types signatures * @return true if the method is found in the element, false otherwise */ private boolean hasMethod(IRubyElement element, Object[] args) { try { if (args.length > 1) { IType type = getType(element); if (type != null && type.exists()) { String name = (String) args[0]; String signature = (String) args[1]; String[] parms = signature.split(","); IMethod candidate = type.getMethod(name, parms); if (candidate.exists()) { // check return type // check modifiers if (args.length > 2) { String modifierText = (String) args[2]; String[] modifiers = modifierText.split(" "); //$NON-NLS-1$ for (int j = 0; j < modifiers.length; j++) { String modifier = modifiers[j]; if (modifier.equals("public") && !candidate.isPublic()) return false; else if (modifier.equals("private") && !candidate.isPrivate()) return false; else if (modifier.equals("protected") && !candidate.isProtected()) return false; else if (modifier.equals("singleton") && !candidate.isSingleton()) return false; } return true; } } } } } catch (RubyModelException e) {} return false; } /** * Determines if the element has qname as a parent class * @param element the element to check for the parent class definition * @param qname the fully qualified name of the (potential) parent class * @return true if qname is a parent class, false otherwise */ private boolean hasSuperclass(IRubyElement element, String qname) { try { IType type = getType(element); if(type != null) { IType[] stypes = type.newSupertypeHierarchy(new NullProgressMonitor()).getAllSuperclasses(type); for(int i = 0; i < stypes.length; i++) { if(stypes[i].getFullyQualifiedName().equals(qname) || stypes[i].getElementName().equals(qname)) { return true; } } } } catch(RubyModelException e) {} return false; } /** * determines if the project selected has the specified nature * @param resource the resource to get the project for * @param ntype the specified nature type * @return true if the specified nature matches the project, false otherwise */ private boolean hasProjectNature(IRubyElement element, String ntype) { if(element != null) { IResource resource = element.getResource(); if (resource == null) { resource = element.getRubyProject().getProject(); } if(resource != null) { return hasProjectNature(resource, ntype); } } return false; } /** * gets the type of the IRubyElement * @param element the element to inspect * @return the type * @throws RubyModelException */ private IType getType(IRubyElement element) throws RubyModelException { IType type = null; if (element instanceof IRubyScript) { type= ((IRubyScript) element).findPrimaryType(); } else if (element instanceof IType) { type = (IType) element; } else if (element instanceof IMember) { type = ((IMember)element).getDeclaringType(); } return type; } }