diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Member.java')
-rw-r--r-- | bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Member.java | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Member.java b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Member.java new file mode 100644 index 000000000..5d442f62c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.metadata/src/org/eclipse/equinox/internal/p2/metadata/expression/Member.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2009 Cloudsmith Inc. and others. + * 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: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.metadata.expression; + +import java.lang.reflect.*; +import org.eclipse.equinox.p2.metadata.expression.IEvaluationContext; +import org.eclipse.equinox.p2.metadata.expression.IExpressionVisitor; + +/** + * <p>An expression that performs member calls to obtain some value + * from some object instance. It uses standard bean semantics so + * that an attempt to obtain "value" will cause an + * attempt to call <code>getValue()</code> and if no such method + * exists, <code>isValue()</code> and if that doesn't work either, + * <code>value()</code>.</p> + */ +public abstract class Member extends Unary { + + public static final class DynamicMember extends Member { + private static final String GET_PREFIX = "get"; //$NON-NLS-1$ + private static final String IS_PREFIX = "is"; //$NON-NLS-1$ + private static final Class<?>[] NO_ARG_TYPES = new Class[0]; + + private Class<?> lastClass; + + private Method method; + private String methodName; + + DynamicMember(Expression operand, String name) { + super(operand, name, Expression.emptyArray); + if (!(name.startsWith(GET_PREFIX) || name.startsWith(IS_PREFIX))) + name = GET_PREFIX + Character.toUpperCase(name.charAt(0)) + name.substring(1); + this.methodName = name; + } + + public Object evaluate(IEvaluationContext context) { + return invoke(operand.evaluate(context)); + } + + public Object invoke(Object self) { + if (self == null) + throw new IllegalArgumentException("Cannot access member \'" + name + "\' in null"); //$NON-NLS-1$//$NON-NLS-2$ + + if (self instanceof MemberProvider) + return ((MemberProvider) self).getMember(name); + + Class<?> c = self.getClass(); + if (lastClass == null || !lastClass.isAssignableFrom(c)) { + Method m; + for (;;) { + try { + m = c.getMethod(methodName, NO_ARG_TYPES); + if (!Modifier.isPublic(m.getModifiers())) + throw new NoSuchMethodException(); + break; + } catch (NoSuchMethodException e) { + if (methodName.startsWith(GET_PREFIX)) + // Switch from using getXxx() to isXxx() + methodName = IS_PREFIX + Character.toUpperCase(name.charAt(0)) + name.substring(1); + else if (methodName.startsWith(IS_PREFIX)) + // Switch from using isXxx() to xxx() + methodName = name; + else + throw new IllegalArgumentException("Cannot find a public member \'" + name + "\' in a " + self.getClass().getName()); //$NON-NLS-1$//$NON-NLS-2$ + } + } + + // Since we already checked that it's public. This will speed + // up the calls a bit. + m.setAccessible(true); + lastClass = c; + method = m; + } + + Exception checked; + try { + return method.invoke(self, NO_ARGS); + } catch (IllegalArgumentException e) { + throw e; + } catch (IllegalAccessException e) { + checked = e; + } catch (InvocationTargetException e) { + Throwable cause = e.getTargetException(); + if (cause instanceof RuntimeException) + throw (RuntimeException) cause; + if (cause instanceof Error) + throw (Error) cause; + checked = (Exception) cause; + } + throw new RuntimeException("Problem invoking " + methodName + " on a " + self.getClass().getName(), checked); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + static final Object[] NO_ARGS = new Object[0]; + + static Member createDynamicMember(Expression operand, String name) { + return new DynamicMember(operand, name); + } + + protected final Expression[] argExpressions; + + final String name; + + protected Member(Expression operand, String name, Expression[] args) { + super(operand); + this.name = name; + this.argExpressions = args; + } + + public boolean accept(IExpressionVisitor visitor) { + if (super.accept(visitor)) + for (int idx = 0; idx < argExpressions.length; ++idx) + if (!argExpressions[idx].accept(visitor)) + return false; + return true; + } + + public int compareTo(Expression e) { + int cmp = super.compareTo(e); + if (cmp == 0) { + cmp = name.compareTo(((Member) e).name); + if (cmp == 0) + cmp = compare(argExpressions, ((Member) e).argExpressions); + } + return cmp; + } + + public boolean equals(Object o) { + if (super.equals(o)) { + Member mo = (Member) o; + return name.equals(mo.name) && equals(argExpressions, mo.argExpressions); + } + return false; + } + + public int getExpressionType() { + return TYPE_MEMBER; + } + + public String getName() { + return name; + } + + public String getOperator() { + return OPERATOR_MEMBER; + } + + public int getPriority() { + return PRIORITY_MEMBER; + } + + public int hashCode() { + int result = 31 + name.hashCode(); + result = 31 * result + operand.hashCode(); + return 31 * result + hashCode(argExpressions); + } + + public void toString(StringBuffer bld, Variable rootVariable) { + if (operand != rootVariable) { + appendOperand(bld, rootVariable, operand, getPriority()); + bld.append('.'); + } + bld.append(name); + if (argExpressions.length > 0) { + bld.append('('); + elementsToString(bld, rootVariable, argExpressions); + bld.append(')'); + } + } +} |