Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: b7d1ecce87e9542b06ccebca46ed018b5f2f8ce5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*******************************************************************************
 * Copyright (c) 2010, 2017 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.util.*;
import org.eclipse.equinox.p2.metadata.*;
import org.eclipse.equinox.p2.metadata.expression.*;
import org.osgi.framework.Filter;

/**
 * <p>A class that performs &quot;matching&quot; The actual algorithm used for
 * performing the match varies depending on the types of the items to match.</p>
 * <p>The following things can be matched:</p>
 * <table border="1" cellpadding="3">
 * <tr><th>LHS</th><th>RHS</th><th>Implemented as</th></tr>
 * <tr><td>{@link String}</td><td>{@link SimplePattern}</td><td>rhs.isMatch(lhs)</td></tr>
 * <tr><td>{@link String}</td><td>{@link LDAPApproximation}</td><td>rhs.isMatch(lhs)</td></tr>
 * <tr><td>&lt;any&gt;</td><td>{@link Class}</td><td>rhs.isInstance(lhs)</td></tr>
 * <tr><td>{@link Class}</td><td>{@link Class}</td><td>rhs.isAssignableFrom(lhs)</td></tr>
 * </table>
 */
public class Matches extends Binary {
	protected Matches(Expression lhs, Expression rhs) {
		super(lhs, rhs);
	}

	@Override
	public Object evaluate(IEvaluationContext context) {
		return Boolean.valueOf(match(lhs.evaluate(context), rhs.evaluate(context)));
	}

	@SuppressWarnings({"unchecked", "rawtypes"})
	protected boolean match(Object lval, Object rval) {
		if (lval == null || rval == null)
			return false;

		if (rval instanceof IRequirement) {
			IRequirement requirement = (IRequirement) rval;
			if (lval instanceof IInstallableUnit)
				return Boolean.valueOf(((IInstallableUnit) lval).satisfies(requirement));
		} else if (rval instanceof VersionRange) {
			VersionRange range = (VersionRange) rval;
			if (lval instanceof Version)
				return Boolean.valueOf(range.isIncluded((Version) lval));
			if (lval instanceof String)
				return range.isIncluded(Version.create((String) lval));
		} else if (rval instanceof SimplePattern) {
			if (lval instanceof CharSequence)
				return ((SimplePattern) rval).isMatch((CharSequence) lval);
			if (lval instanceof Character || lval instanceof Number || lval instanceof Boolean)
				return ((SimplePattern) rval).isMatch(lval.toString());
		} else if (rval instanceof LDAPFilter) {
			return ((LDAPFilter) rval).isMatch(MemberProvider.create(lval, true));
		} else if (rval instanceof Filter) {
			if (lval instanceof IInstallableUnit)
				return Boolean.valueOf(((Filter) rval).match(new Hashtable<>(((IInstallableUnit) lval).getProperties())));
			// TODO Below we use raw types for simplicity;
			// we could convert to Dictionary<String, ?> but that is work and the filter impl
			// must still handle (and ignore) non String keys.
			if (lval instanceof Dictionary<?, ?>)
				return Boolean.valueOf(((Filter) rval).match((Dictionary<String, ?>) lval));
			if (lval instanceof Map<?, ?>)
				return Boolean.valueOf(((Filter) rval).match(new Hashtable((Map<?, ?>) lval)));
		} else if (rval instanceof Locale) {
			if (lval instanceof String)
				return Boolean.valueOf(matchLocaleVariants((Locale) rval, (String) lval));
		} else if (rval instanceof IMatchExpression<?>) {
			IMatchExpression<Object> me = (IMatchExpression<Object>) rval;
			return me.isMatch(lval);
		} else if (rval instanceof IUpdateDescriptor) {
			if (lval instanceof IInstallableUnit)
				return Boolean.valueOf(((IUpdateDescriptor) rval).isUpdateOf((IInstallableUnit) lval));
		} else if (rval instanceof LDAPApproximation) {
			if (lval instanceof CharSequence)
				return ((LDAPApproximation) rval).isMatch((CharSequence) lval);
			if (lval instanceof Character || lval instanceof Number || lval instanceof Boolean)
				return ((LDAPApproximation) rval).isMatch(lval.toString());
		} else if (rval instanceof Class<?>) {
			Class<?> rclass = (Class<?>) rval;
			return lval instanceof Class<?> ? rclass.isAssignableFrom((Class<?>) lval) : rclass.isInstance(lval);
		}
		throw new IllegalArgumentException("Cannot match a " + lval.getClass().getName() + " with a " + rval.getClass().getName()); //$NON-NLS-1$//$NON-NLS-2$
	}

	@Override
	public int getExpressionType() {
		return TYPE_MATCHES;
	}

	@Override
	public String getOperator() {
		return OPERATOR_MATCHES;
	}

	@Override
	public void toLDAPString(StringBuffer buf) {
		if (!(rhs instanceof Literal))
			throw new UnsupportedOperationException();

		boolean escapeWild = true;
		Object val = rhs.evaluate(null);
		buf.append('(');
		appendLDAPAttribute(buf);
		if (val instanceof LDAPApproximation) {
			buf.append(getOperator());
		} else if (val instanceof SimplePattern) {
			buf.append('=');
			escapeWild = false;
		} else
			throw new UnsupportedOperationException();
		appendLDAPEscaped(buf, val.toString(), escapeWild);
		buf.append(')');
	}

	private static boolean equals(String a, String b, int startPos, int endPos) {
		if (endPos - startPos != b.length())
			return false;

		int bidx = 0;
		while (startPos < endPos)
			if (a.charAt(startPos++) != b.charAt(bidx++))
				return false;
		return true;
	}

	private static boolean matchLocaleVariants(Locale rval, String lval) {
		int uscore = lval.indexOf('_');
		if (uscore < 0)
			// No country and no variant. Just match language
			return lval.equals(rval.getLanguage());

		if (!equals(lval, rval.getLanguage(), 0, uscore))
			// Language part doesn't match. Give up.
			return false;

		// Check country and variant
		int countryStart = uscore + 1;
		uscore = lval.indexOf('_', countryStart);
		return uscore < 0 ? equals(lval, rval.getCountry(), countryStart, lval.length()) //
				: equals(lval, rval.getCountry(), countryStart, uscore) && equals(lval, rval.getVariant(), uscore + 1, lval.length());
	}

}

Back to the top