org.eclipse.core.expressions.package.html Maven / Gradle / Ivy
Package-level Javadoc
Application programming interfaces for the expression language.
Package Specification
The package provides API and implementation classes to define a unified
XML expression language. The expression language isn't only for extension
points, it can be used in any XML document that supports enablement
expressions.
XML expression language
The XML expression language consists of the following predefined
expression tags. The set is open and can be extended to customize the
expression language.
Boolean operators
The expression language provides standard expressions for the Boolean
operators and, or and not.
Instanceof expression
The most frequently used check in current extension points is one to
test if an object conforms to a certain type. The common XML expression
language provides a special XML element to represent instance of checks.
A typical usage looks as follows:
<instanceof value="org.eclipse.jdt.core.IJavaElement"/>
The above expression tests, if the object under inspection (in most
cases the element selected in the user interface) is of instance
"org.eclipse.jdt.core.IJavaElement".
Besides instance of checks the new expression language defines an
extensible <test> element to support property testing. The
<test> element is comparable to the <filter> element used in
Platform/UI. The test element is used as follows:
<and>
<instanceof value="org.eclipse.core.resources.IFile"/>
<test property="org.demo.matchesPattern" value="*.html"/>
</and>
The above expression evaluates to true if the object under inspection
is of type "org.eclipse.core.resources.IFile" and its file name matches
the pattern "*.html". But who actually provides the code to do the name
pattern test? Predefining a set of properties to test is too limiting.
The set of tests must be open. Property testers are added to the system
using a special extension point propertyTesters
.
The above matchesPattern property is added to the system in the
following way:
<extension point="org.eclipse.core.expressions.propertyTesters">
<propertyTester
id="org.eclipse.jdt.ui.IResourceTypeExtender"
type="org.eclipse.core.resources.IResource"
namespace="org.demo"
properties="matchesPattern, ...."
class="org.eclipse....ResourcePropertyTester">
</propertyTester>
</extension>
The major characteristics of the extensible test mechanism are:
- types are enriched with new properties using a property tester,
meaning that the code of the actual property test is provided by a
different class.
- a property tester implements a set of properties.
- property testers and their properties are defined in XML as
extension points. This is required to check if an extender provides a
property without having to activate it (e.g. load the plug-in).
- properties belong to a name space. This ensures that two sibling
plug-ins can define the same property without causing any ambiguity. If
a property is defined more than once for a name space then one of the
testers is randomly chosen to test the property. Inheritance only
works within the same name space. If, for example, there is a property
isPublic
defined in the
namespace org.myNamespace
for type org.eclipse.core.IMethod
then this property will not override the property isPublic
in the namespace org.yourNamespace
for type org.eclipse.core.IMember
.
- testing for an unknown property results in a core exception. This
is a programming error.
The attributes of the propertyTester element have the following
meaning:
- id: a unique id
- type: the type which gets "enriched" with new methods
- namespace: the name space the properties belong to
- properties: the comma separated list of properties provided by the
tester.
- class: the implementing class
The concrete implementation for the above property tester looks like
this:
public class ResourcePropertyTester extends PropertyTester {
private static final String PROPERTY_MATCHES_PATTERN= "matchesPattern"; //$NON-NLS-1$
public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
IResource resource= (IResource)receiver;
if (PROPERTY_MATCHES_PATTERN.equals(method)) {
String fileName= resource.getName();
StringMatcher matcher= new StringMatcher((String)expectedValue, false, false);
return expectedValue == null
? matcher.match(fileName)
: matcher.match(filename) == ((Boolean)expectedValue).booleanValue();
} else if (...) {
}
Assert.isTrue(false);
return false;
}
}
The string value provided by the value attribute is converted into a
Java object using the following rules:
- the string "true" is converted into Boolean.TRUE
- the string "false" is converted into Boolean.FALSE
- if the string contains a dot then the interpreter tries to convert
the value into a Float object. If this fails the string is treated as a
java.lang.String
- if the string only consists of numbers then the interpreter
converts the value in an Integer object.
- in all other cases the string is treated as a java.lang.String
- the conversion of the string into a Boolean, Float, or Integer can
be suppressed by surrounding the string with single quotes. For
example, the attribute value="'true'" is converted into the
string "true"
Sometimes a property test needs additional arguments to determine the
exact property to test. If this is the case the arguments can be passed
using the additional args attribute. An example which validates a name
using the method IWorkspace.validateName looks as follows:
<test property="org.demo.validateName" args="/org.eclipse.demo/A.java, FILE"/>
With expression
Test expressions don't allow to specify the object they inspect. They
work on a default object, which for most extension points is the object
selected in the user interface. However, the enablement logic of some
extension points need to test other objects as well. For example a Java
refactoring participant tests if the list of affected projects contains
a project with the Java nature:
<with variable="affectedProjects">
<iterate operator="or">
<test property="org.demo.projectNature" value="org.eclipse.jdt.core.javanature"/>
</iterate>
</with>
The plug-in that evaluates the extension point is responsible for
providing the set of available variables. For example, the code that
evaluates refactoring participants provides the follow variables:
- selection: its value is a collection containing the objects
to be refactored
- affectedProjects: its value is a collection containing the
projects affected by the refactoring
- defaultVariable: will be used if no with expression element
is active. Is an alias for the variable selection.
If the variable doesn't exist, the with expression will throw a core
exception.
Resolve expression
The resolve expression is comparable to the with expression, but it allows resolving the variable dynamically and to pass additional arguments needed to resolve the argument. For example to resolve the plug-in descriptor for a specific plug-in the following XML element can be used:
<resolve variable="pluginDescriptor" args="org.eclipse.core.runtime">
<test property="org.demo.isActive"/>
</adapt>
The actual resolving is delegated to the evaluation context used to evaluate the expressions. See below on how to evaluate an expression and how to create an evaluation context.
Adapt expression
The adapt expression can be used to adapt the object to be inspected
to an object of a different type using the adapter mechanism provided by
the platform. The example below adapts the object to be inspected to an
IType and then checks if the type is public:
<adapt type="org.eclipse.jdt.core.IType">
<test property="org.demo.isPrivate"/>
</adapt>
Like the with expression the adapt expression changes the object to
inspect for all its children. The new object is the one returned from
IAdapter.getAdapter(). If the adaption fails, the expression evaluates
to false.
The adapt expression is implemented based on the IAdapterManager API
hasAdapter(Object, String)
and getAdapter(Object, String)
.
This ensures that the right class loader is taken to convert the type name into a
corresponding Class object.
However, using this API requires that the adapter factory providing the actual adapter
is registered in XML using the extension point "org.eclipse.core.runtime.adapters".
Assuming that there is an adapter that converts resources with the extension .java into IType objects,
the adapter must be declared in XML to make the above adapt expression work correctly.
The corresponding adapter definition looks like this:
<extension point="org.eclipse.core.runtime.adapters">
<factory
class="org.demo.MyAdapterFactory"
adaptableType="org.eclipse.core.resources.IFile">
<adapter type="org.eclipse.jdt.core.IType"/>
</factory>
</extension>
SytemTest expression
There is a special XML element to test system properties.
<systemTest property="os.name" value="Windows XP"/>
<systemTest property="os.version" value="5.1"/>
Dealing with collection of elements
Several expressions are evaluated on a collection of objects (for
example refactoring participants, menu contributions, ...). Up to now, the
iteration over collections was implicitly coded into the enclosing XML
element, which isn't part of the expression itself. The new mechanism
provides explicit expression elements to deal with collections of
objects. The following element
<count value="*"/>
is used to check the number of objects in a collection, and the syntax
of the attribute value is equal to the enablesFor attribute used for
object contributions. To iterate over a collection, an element
<iterate operator="...">
is provided. The operator attribute can either be "and" or "or". It
determines how the evaluation results of all objects in the list are
combined. The default operator is "and". Using these expression the
enablement of a typical contribution can be described as follows:
<with variable="selection">
<count value="+"/>
<iterate operator="and"/>
<adapt type="org.eclipse.core.resources.IFile">
<test property="matchesName" value="*.gif"/>
<test property="canDelete"/>
</adapt>
</iterate>
</with>
The expression only evaluates to true if the selection contains one
or more objects and all objects fulfill the expression defined by the
adapt element.
Enablement expression
XML expressions are mostly used to define the availability of an
extension point contribution, but they can be used in any XML document
that allows expressions. To separate the expression from other
child elements the common expression language provides an enablement
element. Its use is as follows:
<renameParticipant
id="launchConfigUpdater"
class="org.eclipse...LaunchConfigUpdater">
<enablement>
...
</enablement>
</renameParticipant>
Most of the time child expression will be combined using the and
operator. To avoid deep nesting XML "and" will be the default for
combining children. It can therefore be omitted. The same applies to the
adapt, iterate, and enablement expression defined in the following
sections.
Extension Point Schema
An extension point schema exists for the property tester extension
point and for the expression language itself. The schema for the
expression language can be included into other schema files using
the following include element:
<include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
Converting XML elements into expressions
XML elements can be converted into corresponding expression objects using the class ExpressionConverter.
If only expression tags from the common expression language are used, then the standard expression converter can be used.
The following example converts the configuration element representing an enablement element into an expression:
IConfigurationElement enablementElement= ...;
Expression expression=
ExpressionConverter.getDefault().perform(enablementElement);
Evaluating an expression
Expressions are evaluated by calling Expression.evaluate(...);
. The evaluation
context passed to the evaluate method has to be set up by the plug-in that reads an extension point.
The plug-in is responsible to set up the default variable and all the other variable used in
with expressions. The example below creates a special evaluation context and uses this context to
evaluate an expression:
EvaluationContext context= new EvaluationContext(null, defaultVariable) {
public Object resolveVariable(String name, Object[] args) throws CoreException {
// do special resolving
}
}
The actual evaluation is done by calling:
EvaluationResult= expression.evaluate(context);