Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 249496 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/emf/validation/internal/l10n/ValidationMessages.java (-1 / +3 lines)
Lines 1-5 Link Here
1
/******************************************************************************
1
/******************************************************************************
2
 * Copyright (c) 2005, 2007 IBM Corporation and others.
2
 * Copyright (c) 2005, 2008 IBM Corporation, Zeligsoft Inc., and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 7-12 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *    IBM Corporation - initial API and implementation 
9
 *    IBM Corporation - initial API and implementation 
10
 *    Zeligsoft - Bug 249496
10
 ****************************************************************************/
11
 ****************************************************************************/
11
12
12
package org.eclipse.emf.validation.internal.l10n;
13
package org.eclipse.emf.validation.internal.l10n;
Lines 78-83 Link Here
78
	public static String binding_noSuchContext_ERROR_;
79
	public static String binding_noSuchContext_ERROR_;
79
	public static String binding_noConstraintRef_WARN_;
80
	public static String binding_noConstraintRef_WARN_;
80
	public static String binding_noCategoryRef_WARN_;
81
	public static String binding_noCategoryRef_WARN_;
82
	public static String binding_noClientContextRef_WARN_;
81
	public static String mode_live;
83
	public static String mode_live;
82
	public static String mode_batch;
84
	public static String mode_batch;
83
	public static String mode_unknown;
85
	public static String mode_unknown;
(-)src/org/eclipse/emf/validation/internal/l10n/ValidationMessages.properties (-1 / +9 lines)
Lines 1-5 Link Here
1
###############################################################################
1
###############################################################################
2
# Copyright (c) 2003, 2007 IBM Corporation and others.
2
# Copyright (c) 2003, 2008 IBM Corporation, Zeligsoft Inc., and others.
3
# All rights reserved. This program and the accompanying materials
3
# All rights reserved. This program and the accompanying materials
4
# are made available under the terms of the Eclipse Public License v1.0
4
# are made available under the terms of the Eclipse Public License v1.0
5
# which accompanies this distribution, and is available at
5
# which accompanies this distribution, and is available at
Lines 7-12 Link Here
7
# 
7
# 
8
# Contributors:
8
# Contributors:
9
#     IBM Corporation - initial API and implementation
9
#     IBM Corporation - initial API and implementation
10
#     Zeligsoft - Bug 249496
10
# 
11
# 
11
# $Id$
12
# $Id$
12
###############################################################################
13
###############################################################################
Lines 381-386 Link Here
381
binding_noCategoryRef_WARN_= Constraint category binding for client context \
382
binding_noCategoryRef_WARN_= Constraint category binding for client context \
382
	{0} does not reference a category path in plug-in {1}.
383
	{0} does not reference a category path in plug-in {1}.
383
384
385
# Indicates that a client context extension does not actually specify any context.
386
# args:
387
#   0 - the client context ID of the binding
388
#   1 - the ID of the plug-in defining the offending extension
389
binding_noClientContextRef_WARN_= Constraint binding for client context {0} does \
390
	not reference an extended client context in plug-in {1}.
391
384
392
385
# ==============================================================================
393
# ==============================================================================
386
# Translation Instruction: section to be translated
394
# Translation Instruction: section to be translated
(-)src/org/eclipse/emf/validation/internal/EMFModelValidationStatusCodes.java (-2 / +4 lines)
Lines 1-12 Link Here
1
/******************************************************************************
1
/******************************************************************************
2
 * Copyright (c) 2003, 2007 IBM Corporation and others.
2
 * Copyright (c) 2003, 2008 IBM Corporation, Zeligsoft Inc., and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *    IBM Corporation - initial API and implementation 
9
 *    IBM Corporation - initial API and implementation
10
 *    Zeligsoft - Bug 249496
10
 ****************************************************************************/
11
 ****************************************************************************/
11
12
12
13
Lines 75-80 Link Here
75
	public static final int BINDING_NO_SUCH_CLIENT = 121;
76
	public static final int BINDING_NO_SUCH_CLIENT = 121;
76
	public static final int BINDING_NO_CONSTRAINT = 122;
77
	public static final int BINDING_NO_CONSTRAINT = 122;
77
	public static final int BINDING_NO_CATEGORY = 123;
78
	public static final int BINDING_NO_CATEGORY = 123;
79
	public static final int BINDING_NO_CLIENT_CONTEXT = 124;
78
	
80
	
79
	public static final int LISTENER_UNCAUGHT_EXCEPTION = 130;
81
	public static final int LISTENER_UNCAUGHT_EXCEPTION = 130;
80
	
82
	
(-)src/org/eclipse/emf/validation/internal/service/ClientContextManager.java (-34 / +50 lines)
Lines 7-13 Link Here
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *    IBM Corporation - initial API and implementation
9
 *    IBM Corporation - initial API and implementation
10
 *    Zeligsoft - Bug 137213
10
 *    Zeligsoft - Bugs 137213, 249496
11
 *    Borland Software - Bug 137213
11
 *    Borland Software - Bug 137213
12
 ****************************************************************************/
12
 ****************************************************************************/
13
13
Lines 52-59 Link Here
52
	private static final String E_BINDING = "binding"; //$NON-NLS-1$
52
	private static final String E_BINDING = "binding"; //$NON-NLS-1$
53
	private static final String A_CONTEXT = "context"; //$NON-NLS-1$
53
	private static final String A_CONTEXT = "context"; //$NON-NLS-1$
54
	
54
	
55
	private static final String A_CONSTRAINT = "constraint"; //$NON-NLS-1$
55
	private static final String E_CONSTRAINT = "constraint"; //$NON-NLS-1$
56
	private static final String A_CATEGORY = "category"; //$NON-NLS-1$
56
	private static final String E_CATEGORY = "category"; //$NON-NLS-1$
57
	private static final String E_EXTEND_CLIENT_CONTEXT = "extendClientContext"; //$NON-NLS-1$
58
	private static final String E_EXCLUDE_CONSTRAINT = "excludeConstraint"; //$NON-NLS-1$
59
	private static final String E_EXCLUDE_CATEGORY = "excludeCategory"; //$NON-NLS-1$
57
	private static final String A_REF = "ref"; //$NON-NLS-1$
60
	private static final String A_REF = "ref"; //$NON-NLS-1$
58
	
61
	
59
	private static final ClientContextManager INSTANCE = new ClientContextManager();
62
	private static final ClientContextManager INSTANCE = new ClientContextManager();
Lines 153-159 Link Here
153
	 *    selector matches this element
156
	 *    selector matches this element
154
	 */
157
	 */
155
	public Collection<IClientContext> getClientContextsFor(EObject eObject) {
158
	public Collection<IClientContext> getClientContextsFor(EObject eObject) {
156
		Collection<IClientContext> result = new java.util.ArrayList<IClientContext>();
159
		Set<IClientContext> result = new java.util.HashSet<IClientContext>();
157
		
160
		
158
		EvaluationContext ctx = new EvaluationContext(null, eObject);
161
		EvaluationContext ctx = new EvaluationContext(null, eObject);
159
162
Lines 197-202 Link Here
197
			}
200
			}
198
		}
201
		}
199
		
202
		
203
		if (result.size() > 1) {
204
			ClientContext.pruneExtensions(result);
205
		}
206
		
200
		return result;
207
		return result;
201
	}
208
	}
202
	
209
	
Lines 341-347 Link Here
341
			// add the constraint to all default contexts so that we don't do
348
			// add the constraint to all default contexts so that we don't do
342
			//   this computation again
349
			//   this computation again
343
			for (ClientContext next : defaultContexts) {
350
			for (ClientContext next : defaultContexts) {
344
				next.bindConstraint(id);
351
				next.includeConstraint(id);
345
			}
352
			}
346
		}
353
		}
347
		
354
		
Lines 447-493 Link Here
447
	 * @param config a particular <code>&lt;binding&gt;</config> element
454
	 * @param config a particular <code>&lt;binding&gt;</config> element
448
	 */
455
	 */
449
	private void configureBindings(ClientContext context, IConfigurationElement config) {
456
	private void configureBindings(ClientContext context, IConfigurationElement config) {
450
		String id = config.getAttribute(A_CONSTRAINT);
457
		String id = config.getAttribute(E_CONSTRAINT);
451
		
458
		
452
		if (id != null) {
459
		if (id != null) {
453
			context.bindConstraint(id);
460
			context.includeConstraint(id);
454
		}
461
		}
455
		
462
		
456
		id = config.getAttribute(A_CATEGORY);
463
		id = config.getAttribute(E_CATEGORY);
457
		
464
		
458
		if (id != null) {
465
		if (id != null) {
459
			context.bindCategory(id);
466
			context.includeCategory(id);
460
		}
461
		
462
		IConfigurationElement[] children = config.getChildren(A_CONSTRAINT);
463
		for (IConfigurationElement element : children) {
464
			final String ref = element.getAttribute(A_REF);
465
			
466
			if (ref == null) {
467
				Log.warningMessage(
468
					EMFModelValidationStatusCodes.BINDING_NO_CONSTRAINT,
469
					ValidationMessages.binding_noConstraintRef_WARN_,
470
					new Object[] {
471
						context.getId(),
472
						config.getDeclaringExtension().getNamespaceIdentifier()});
473
			} else {
474
				context.bindConstraint(ref);
475
			}
476
		}
467
		}
477
		
468
		
478
		children = config.getChildren(A_CATEGORY);
469
		IConfigurationElement[] children = config.getChildren();
479
		for (IConfigurationElement element : children) {
470
		for (IConfigurationElement element : children) {
471
			final String name = element.getName();
480
			final String ref = element.getAttribute(A_REF);
472
			final String ref = element.getAttribute(A_REF);
481
			
473
			
482
			if (ref == null) {
474
			if (ref == null) {
483
				Log.errorMessage(
475
				if (E_CONSTRAINT.equals(name) || E_EXCLUDE_CONSTRAINT.equals(name)) {
484
					EMFModelValidationStatusCodes.BINDING_NO_CATEGORY,
476
					Log.warningMessage(
485
					ValidationMessages.binding_noCategoryRef_WARN_,
477
						EMFModelValidationStatusCodes.BINDING_NO_CONSTRAINT,
486
					new Object[] {
478
						ValidationMessages.binding_noConstraintRef_WARN_,
487
						context.getId(),
479
						new Object[] {
488
						config.getDeclaringExtension().getNamespaceIdentifier()});
480
							context.getId(),
489
			} else {
481
							config.getDeclaringExtension().getNamespaceIdentifier()});
490
				context.bindCategory(ref);
482
				} else if (E_EXTEND_CLIENT_CONTEXT.equals(name)) {
483
					Log.warningMessage(
484
						EMFModelValidationStatusCodes.BINDING_NO_CLIENT_CONTEXT,
485
						ValidationMessages.binding_noClientContextRef_WARN_,
486
						new Object[] {
487
							context.getId(),
488
							config.getDeclaringExtension().getNamespaceIdentifier()});
489
				} else {
490
					Log.errorMessage(
491
						EMFModelValidationStatusCodes.BINDING_NO_CATEGORY,
492
						ValidationMessages.binding_noCategoryRef_WARN_,
493
						new Object[] {
494
							context.getId(),
495
							config.getDeclaringExtension().getNamespaceIdentifier()});
496
				}
497
			} else if (E_CONSTRAINT.equals(name)) {
498
				context.includeConstraint(ref);
499
			} else if (E_CATEGORY.equals(name)) {
500
				context.includeCategory(ref);
501
			} else if (E_EXTEND_CLIENT_CONTEXT.equals(name)) {
502
				context.extendClientContext(ref);
503
			} else if (E_EXCLUDE_CONSTRAINT.equals(name)) {
504
				context.excludeConstraint(ref);
505
			} else if (E_EXCLUDE_CATEGORY.equals(name)) {
506
				context.excludeCategory(ref);
491
			}
507
			}
492
		}
508
		}
493
	}
509
	}
(-)src/org/eclipse/emf/validation/internal/service/ClientContext.java (-57 / +498 lines)
Lines 1-25 Link Here
1
/******************************************************************************
1
/******************************************************************************
2
 * Copyright (c) 2005, 2007 IBM Corporation and others.
2
 * Copyright (c) 2005, 2008 IBM Corporation, Zeligsoft Inc., and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
7
 *
8
 * Contributors:
8
 * Contributors:
9
 *    IBM Corporation - initial API and implementation 
9
 *    IBM Corporation - initial API and implementation
10
 *    Zeligsoft - Bug 249496
10
 ****************************************************************************/
11
 ****************************************************************************/
11
12
12
package org.eclipse.emf.validation.internal.service;
13
package org.eclipse.emf.validation.internal.service;
13
14
14
import java.util.Collection;
15
import java.util.Collection;
15
import java.util.Iterator;
16
import java.util.Map;
16
import java.util.Set;
17
import java.util.Set;
17
18
18
import org.eclipse.core.runtime.CoreException;
19
import org.eclipse.core.runtime.CoreException;
19
import org.eclipse.core.runtime.IConfigurationElement;
20
import org.eclipse.core.runtime.IConfigurationElement;
20
import org.eclipse.core.runtime.IStatus;
21
import org.eclipse.core.runtime.IStatus;
21
import org.eclipse.core.runtime.Status;
22
import org.eclipse.core.runtime.Status;
22
23
import org.eclipse.emf.validation.internal.EMFModelValidationPlugin;
23
import org.eclipse.emf.validation.internal.EMFModelValidationPlugin;
24
import org.eclipse.emf.validation.internal.EMFModelValidationStatusCodes;
24
import org.eclipse.emf.validation.internal.EMFModelValidationStatusCodes;
25
import org.eclipse.emf.validation.internal.l10n.ValidationMessages;
25
import org.eclipse.emf.validation.internal.l10n.ValidationMessages;
Lines 52-62 Link Here
52
	private final IClientSelector selector;
52
	private final IClientSelector selector;
53
	private final boolean isDefault;
53
	private final boolean isDefault;
54
	
54
	
55
	// set of String constraint IDs that are bound to me
55
	// map of String constraint IDs that are bound to me, the boolean value
56
	private final Set<String> constraintBindings = new java.util.HashSet<String>();
56
	// indicating absolute inclusion or exclusion.  Absence of a value means
57
	// that we still need to compute
58
	private final Map<String, Boolean> constraintBindings = new java.util.HashMap<String, Boolean>();
57
	
59
	
58
	// set of String category IDs that are bound to me
60
	// set of String category IDs that are bound to me
59
	private final Set<String> categoryBindings = new java.util.HashSet<String>();
61
	private BindingFilter filter = BindingFilter.NULL;
62
	
63
	private Collection<String> extendedClientContexts = new java.util.ArrayList<String>(
64
		2);
60
	
65
	
61
	/**
66
	/**
62
	 * Initializes me with my XML configuration.
67
	 * Initializes me with my XML configuration.
Lines 235-314 Link Here
235
	}
240
	}
236
241
237
	public boolean includes(IModelConstraint constraint) {
242
	public boolean includes(IModelConstraint constraint) {
238
		boolean result = false;
243
		IConstraintDescriptor desc = constraint.getDescriptor();
239
		
244
		
240
		IConstraintDescriptor descriptor = constraint.getDescriptor();
245
		return (desc != null) && includes(desc);
246
	}
247
	
248
	boolean includes(IConstraintDescriptor constraint) {
249
		Boolean result = constraintBindings.get(constraint.getId());
241
		
250
		
242
		if (descriptor != null) {
251
		if (result == null) {
243
			result = constraintBindings.contains(descriptor.getId());
252
			// cache the result for this constraint
244
			
253
			result = filter.getBinding(constraint);
245
			if (!result && !categoryBindings.isEmpty()) {
254
			constraintBindings.put(constraint.getId(), result);
246
				// look for a bound category
247
				result = hasCategoryBinding(descriptor.getCategories());
248
				
249
				if (result) {
250
					// cache the result for this constraint
251
					bindConstraint(descriptor.getId());
252
				}
253
			}
254
		}
255
		}
255
		
256
		
256
		return result;
257
		return result;
257
	}
258
	}
258
	
259
	
259
	/**
260
	/**
260
	 * Determines whether any of the specified <code>categories</code> is bound
261
	 * Adds a constraint inclusion binding to me.
261
	 * to me.
262
	 * 
262
	 * 
263
	 * @param categories a collection of categories (usually from a constraint)
263
	 * @param constraintId the ID of a constraint that is to be included in me
264
	 * @return <code>true</code> if any of the <code>categories</code> is bound,
265
	 *     or if any of their ancestors is bound; <code>false</code>, otherwise
266
	 */
264
	 */
267
	private boolean hasCategoryBinding(Collection<Category> categories) {
265
	void includeConstraint(String constraintId) {
268
		boolean result = false;
266
		filter = filter.includeConstraint(constraintId);
267
	}
268
269
	/**
270
	 * Adds a constraint exclusion binding to me.
271
	 * 
272
	 * @param constraintId the ID of a constraint that is to be excluded from me
273
	 */
274
	void excludeConstraint(String constraintId) {
275
		filter = filter.excludeConstraint(constraintId);
276
	}
277
278
	/**
279
	 * Adds a constraint category inclusion to me.
280
	 * 
281
	 * @param categoryId the qualified ID (path) of a constraint category that
282
	 *     is to be included in me
283
	 */
284
	void includeCategory(String categoryId) {
285
		filter = filter.includeCategory(categoryId);
286
	}
287
288
	/**
289
	 * Adds a constraint category exclusion to me.
290
	 * 
291
	 * @param categoryId
292
	 *            the qualified ID (path) of a constraint category that is to be
293
	 *            excluded from me
294
	 */
295
	void excludeCategory(String categoryId) {
296
		filter = filter.excludeCategory(categoryId);
297
	}
298
299
	/**
300
	 * Adds a client-context extension to me.
301
	 * 
302
	 * @param clientContextID
303
	 *            a client-context to extend
304
	 */
305
	void extendClientContext(String clientContextID) {
306
		filter = filter.extendClientContext(clientContextID);
269
		
307
		
270
		for (Iterator<Category> iter = categories.iterator(); !result && iter.hasNext();) {
308
		if (!extendedClientContexts.contains(clientContextID)) {
271
			Category category = iter.next();
309
			extendedClientContexts.add(clientContextID);
272
			
273
			result = categoryBindings.contains(category.getPath());
274
			
275
			if (!result) {
276
				// search the ancestors
277
				Category ancestor = category.getParent();
278
				
279
				while ((ancestor != null) && !result) {
280
					result = categoryBindings.contains(ancestor.getPath());
281
					ancestor = ancestor.getParent();
282
				}
283
				
284
				if (result) {
285
					// cache the original category for quicker results on the
286
					//    next constraint that it includes
287
					bindCategory(category.getPath());
288
				}
289
			}
290
		}
310
		}
311
	}
312
	
313
	/**
314
	 * Obtains all of the client-contexts, recursively, that I extend.  As this
315
	 * is recursive, the result includes contexts extended by contexts that I
316
	 * extend.  Note that it is an error for a client-context to, transitively
317
	 * or not, extend itself.
318
	 * 
319
	 * @return all of my extended client contexts
320
	 */
321
	Collection<? extends IClientContext> allExtendedContexts() {
322
		Set<IClientContext> result = new java.util.HashSet<IClientContext>();
323
		
324
		allExtendedContexts(this, result);
291
		
325
		
292
		return result;
326
		return result;
293
	}
327
	}
294
328
295
	/**
329
	/**
296
	 * Binds a constraint to me.
330
	 * Recursive helper for the client-context extension gathering.
297
	 * 
331
	 * 
298
	 * @param constraintId the ID of a constraint that is to be bound to me
332
	 * @param self
333
	 *            an extending client-context
334
	 * @param contexts
335
	 *            its extensions
299
	 */
336
	 */
300
	void bindConstraint(String constraintId) {
337
	private static void allExtendedContexts(ClientContext self,
301
		constraintBindings.add(constraintId);
338
			Set<? super ClientContext> contexts) {
339
		
340
		ClientContextManager mgr = ClientContextManager.getInstance();
341
		
342
		for (String next : self.extendedClientContexts) {
343
			ClientContext extended = (ClientContext) mgr.getClientContext(next);
344
			
345
			if (contexts.add(extended)) {
346
				allExtendedContexts(extended, contexts);
347
			}
348
		}
302
	}
349
	}
303
350
304
	/**
351
	/**
305
	 * Binds a constraint category to me.
352
	 * Removes client-contexts from a set that are extended by other contexts
353
	 * already in the set.
306
	 * 
354
	 * 
307
	 * @param categoryId the qualified ID (path) of a constraint category that
355
	 * @param contexts
308
	 *     is to be bound to me
356
	 *            a set of client-contexts to optimize
309
	 */
357
	 */
310
	void bindCategory(String categoryId) {
358
	static void pruneExtensions(Set<? extends IClientContext> contexts) {
311
		categoryBindings.add(categoryId);
359
		boolean repeat;
360
		do {
361
			repeat = false;
362
			
363
			for (IClientContext next : contexts) {
364
				if ((next instanceof ClientContext)
365
					&& contexts.removeAll(((ClientContext) next)
366
						.allExtendedContexts())) {
367
					
368
					repeat = true;
369
					break;
370
				}
371
			}
372
		} while (repeat);
312
	}
373
	}
313
374
314
	/**
375
	/**
Lines 332-335 Link Here
332
	public String toString() {
393
	public String toString() {
333
		return "ClientContext[" + getId() + ']'; //$NON-NLS-1$
394
		return "ClientContext[" + getId() + ']'; //$NON-NLS-1$
334
	}
395
	}
396
	
397
	
398
	/**
399
	 * A chain-structured constraint-binding filter. Filters are chained in the
400
	 * order in which they are parsed from the extension point. The head of the
401
	 * filter chain applies its filter and, if it doesn't find any match,
402
	 * delegates down the chain. The chain is terminated by the {@link #NULL}
403
	 * filter, which always excludes the constraint.
404
	 * 
405
	 * @author Christian W. Damus (cdamus)
406
	 */
407
	private static class BindingFilter {
408
409
		private BindingFilter next;
410
411
		/** A filter that excludes every constraint. */
412
		static final BindingFilter NULL = new BindingFilter() {
413
414
			boolean getBinding(IConstraintDescriptor constraint) {
415
				return false;
416
			}
417
		};
418
419
		/**
420
		 * Queries whether the specified constraint is definitely included (
421
		 * <code>true</code>) or excluded (<code>false</code>) from the client
422
		 * context. If I don't have definitive knowledge of this constraint, I
423
		 * delegate to the next in the chain.
424
		 * 
425
		 * @param constraint
426
		 *            a constraint descriptor
427
		 * @return whether the constraint is included
428
		 */
429
		boolean getBinding(IConstraintDescriptor constraint) {
430
			return isExcluded(constraint)
431
				? false
432
				: isIncluded(constraint)
433
					? true
434
					: next().getBinding(constraint);
435
		}
436
437
		/**
438
		 * Queries whether I know that a constraint is included.
439
		 * 
440
		 * @param constraint
441
		 *            a constraint descriptor
442
		 * @return <code>true</code> if the constraint is included, or
443
		 *         <code>false</code> if I do not know
444
		 */
445
		boolean isExcluded(IConstraintDescriptor constraint) {
446
			return false;
447
		}
448
449
		/**
450
		 * Queries whether I know that a constraint is excluded.
451
		 * 
452
		 * @param constraint
453
		 *            a constraint descriptor
454
		 * @return <code>true</code> if the constraint is excluded, or
455
		 *         <code>false</code> if I do not know
456
		 */
457
		boolean isIncluded(IConstraintDescriptor constraint) {
458
			return false;
459
		}
460
461
		/**
462
		 * Obtains the next filter in my chain.
463
		 * 
464
		 * @return my next, or <code>null</code> if I am the end of the chain
465
		 */
466
		BindingFilter next() {
467
			return next;
468
		}
469
470
		/**
471
		 * Assigns my next filter.
472
		 * 
473
		 * @param next
474
		 *            my new next
475
		 */
476
		void setNext(BindingFilter next) {
477
			this.next = next;
478
		}
479
480
		/**
481
		 * Obtains a filter, chaining me, that definitively includes the
482
		 * specified category and all of its constraints and sub-categories. The
483
		 * result may be optimized to be myself augmented with this category, if
484
		 * I am a filter of the appropriate kind. Or, the result may be a new
485
		 * filter chain.
486
		 * 
487
		 * @param category
488
		 *            a category to include
489
		 * 
490
		 * @return a filter that includes the category
491
		 */
492
		BindingFilter includeCategory(String category) {
493
			CategoryInclusion result = new CategoryInclusion(category);
494
			result.setNext(this);
495
			return result;
496
		}
497
498
		/**
499
		 * Obtains a filter, chaining me, that definitively excludes the
500
		 * specified category and all of its constraints and sub-categories. The
501
		 * result may be optimized to be myself augmented with this category, if
502
		 * I am a filter of the appropriate kind. Or, the result may be a new
503
		 * filter chain.
504
		 * 
505
		 * @param category
506
		 *            a category to exclude
507
		 * 
508
		 * @return a filter that excludes the category
509
		 */
510
		BindingFilter excludeCategory(String category) {
511
			CategoryExclusion result = new CategoryExclusion(category);
512
			result.setNext(this);
513
			return result;
514
		}
515
516
		/**
517
		 * Obtains a filter, chaining me, that definitively includes the
518
		 * specified constraint. The result may be optimized to be myself
519
		 * augmented with this constraint, if I am a filter of the appropriate
520
		 * kind. Or, the result may be a new filter chain.
521
		 * 
522
		 * @param constraint
523
		 *            a constraint to include
524
		 * 
525
		 * @return a filter that includes the constraint
526
		 */
527
		BindingFilter includeConstraint(String constraint) {
528
			ConstraintInclusion result = new ConstraintInclusion(constraint);
529
			result.setNext(this);
530
			return result;
531
		}
532
533
		/**
534
		 * Obtains a filter, chaining me, that definitively excludes the
535
		 * specified constraint. The result may be optimized to be myself
536
		 * augmented with this constraint, if I am a filter of the appropriate
537
		 * kind. Or, the result may be a new filter chain.
538
		 * 
539
		 * @param constraint
540
		 *            a constraint to exclude
541
		 * 
542
		 * @return a filter that excludes the constraint
543
		 */
544
		BindingFilter excludeConstraint(String constraint) {
545
			ConstraintExclusion result = new ConstraintExclusion(constraint);
546
			result.setNext(this);
547
			return result;
548
		}
549
550
		/**
551
		 * Obtains a filter, chaining me, that inherits the constraints bound to
552
		 * the specified client-context. The result may be optimized to be
553
		 * myself myself augmented with this client-context, if I am a filter of
554
		 * the appropriate kind. Or, the result may be a new filter chain.
555
		 * 
556
		 * @param clientContext
557
		 *            a client-context to extend
558
		 * 
559
		 * @return a filter that extends the client-context
560
		 */
561
		BindingFilter extendClientContext(String clientContext) {
562
			ContextExtension result = new ContextExtension(clientContext);
563
			result.setNext(this);
564
			return result;
565
		}
566
	}
567
568
	/**
569
	 * A binding filter that definitively includes one or more constraints.
570
	 * 
571
	 * @author Christian W. Damus (cdamus)
572
	 */
573
	private static class ConstraintInclusion
574
			extends BindingFilter {
575
576
		private final Set<String> constraints = new java.util.HashSet<String>();
577
578
		ConstraintInclusion(String constraint) {
579
			constraints.add(constraint);
580
		}
581
582
		@Override
583
		boolean isIncluded(IConstraintDescriptor constraint) {
584
			return constraints.contains(constraint.getId());
585
		}
586
587
		@Override
588
		BindingFilter includeConstraint(String constraint) {
589
			constraints.add(constraint);
590
			return this;
591
		}
592
	}
593
594
	/**
595
	 * A binding filter that definitively excludes one or more constraints.
596
	 * 
597
	 * @author Christian W. Damus (cdamus)
598
	 */
599
	private static class ConstraintExclusion
600
			extends BindingFilter {
601
602
		private final Set<String> constraints = new java.util.HashSet<String>();
603
604
		ConstraintExclusion(String constraint) {
605
			constraints.add(constraint);
606
		}
607
608
		@Override
609
		boolean isExcluded(IConstraintDescriptor constraint) {
610
			return constraints.contains(constraint.getId());
611
		}
612
613
		@Override
614
		BindingFilter excludeConstraint(String constraint) {
615
			constraints.add(constraint);
616
			return this;
617
		}
618
	}
619
620
	/**
621
	 * A binding filter that definitively includes one or more categories.
622
	 * 
623
	 * @author Christian W. Damus (cdamus)
624
	 */
625
	private static class CategoryInclusion
626
			extends BindingFilter {
627
628
		private final CategorySet categories;
629
630
		CategoryInclusion(String category) {
631
			categories = new CategorySet(category);
632
		}
633
634
		@Override
635
		boolean isIncluded(IConstraintDescriptor constraint) {
636
			return categories.containsAny(constraint.getCategories());
637
		}
638
639
		@Override
640
		BindingFilter includeCategory(String category) {
641
			categories.add(category);
642
			return this;
643
		}
644
	}
645
646
	/**
647
	 * A binding filter that definitively excludes one or more categories.
648
	 * 
649
	 * @author Christian W. Damus (cdamus)
650
	 */
651
	private static class CategoryExclusion
652
			extends BindingFilter {
653
654
		private final CategorySet categories;
655
656
		CategoryExclusion(String category) {
657
			categories = new CategorySet(category);
658
		}
659
660
		@Override
661
		boolean isExcluded(IConstraintDescriptor constraint) {
662
			return categories.containsAny(constraint.getCategories());
663
		}
664
665
		@Override
666
		BindingFilter excludeCategory(String category) {
667
			categories.add(category);
668
			return this;
669
		}
670
	}
671
672
	private static final class CategorySet {
673
674
		private final Set<String> categories = new java.util.HashSet<String>();
675
676
		CategorySet(String category) {
677
			categories.add(category);
678
		}
679
680
		boolean containsAny(Collection<? extends Category> categories) {
681
			boolean result = false;
682
683
			for (Category next : categories) {
684
				if (contains(next)) {
685
					result = true;
686
					break;
687
				}
688
			}
689
690
			return result;
691
		}
692
693
		boolean contains(Category category) {
694
			boolean result = false;
695
696
			String path = category.getPath();
697
			result = categories.contains(path);
698
699
			if (!result) {
700
				// search the ancestors
701
				Category ancestor = category.getParent();
702
703
				while ((ancestor != null) && !result) {
704
					result = categories.contains(ancestor.getPath());
705
					ancestor = ancestor.getParent();
706
				}
707
708
				if (result) {
709
					// cache the original category for quicker results on the
710
					// next category that it contains
711
					add(path);
712
				}
713
			}
714
715
			return result;
716
		}
717
718
		void add(String category) {
719
			categories.add(category);
720
		}
721
	}
722
723
	/**
724
	 * A binding filter that inherits the bindings of another context.
725
	 * 
726
	 * @author Christian W. Damus (cdamus)
727
	 */
728
	private static class ContextExtension
729
			extends BindingFilter {
730
731
		private final Set<String> extendedContextIDs = new java.util.HashSet<String>();
732
733
		private volatile Set<ClientContext> extendedContexts;
734
735
		ContextExtension(String clientContext) {
736
			extendedContextIDs.add(clientContext);
737
		}
738
739
		@Override
740
		boolean isIncluded(IConstraintDescriptor constraint) {
741
			if (extendedContexts == null) {
742
				// do this lazily because we don't know the order in which
743
				// client-contexts will be discovered in the extension registry
744
				ClientContextManager mgr = ClientContextManager.getInstance();
745
				Set<ClientContext> contexts = new java.util.HashSet<ClientContext>();
746
747
				synchronized (extendedContextIDs) {
748
					for (String next : extendedContextIDs) {
749
						contexts
750
							.add((ClientContext) mgr.getClientContext(next));
751
					}
752
					
753
					extendedContexts = contexts;
754
				}
755
			}
756
			
757
			for (ClientContext extended : extendedContexts) {
758
				if (extended.includes(constraint)) {
759
					return true;
760
				}
761
			}
762
763
			return false;
764
		}
765
766
		@Override
767
		BindingFilter extendClientContext(String clientContext) {
768
			synchronized (extendedContextIDs) {
769
				extendedContexts = null; // purge
770
				extendedContextIDs.add(clientContext);
771
			}
772
773
			return this;
774
		}
775
	}
335
}
776
}
(-)schema/constraintBindings.exsd (-40 / +100 lines)
Lines 1-10 Link Here
1
<?xml version='1.0' encoding='UTF-8'?>
1
<?xml version='1.0' encoding='UTF-8'?>
2
<!-- Schema file written by PDE -->
2
<!-- Schema file written by PDE -->
3
<schema targetNamespace="org.eclipse.emf.validation">
3
<schema targetNamespace="org.eclipse.emf.validation" xmlns="http://www.w3.org/2001/XMLSchema">
4
<annotation>
4
<annotation>
5
      <appInfo>
5
      <appinfo>
6
         <meta.schema plugin="org.eclipse.emf.validation" id="constraintBindings" name="EMF Validation Constraint Bindings"/>
6
         <meta.schema plugin="org.eclipse.emf.validation" id="constraintBindings" name="EMF Validation Constraint Bindings"/>
7
      </appInfo>
7
      </appinfo>
8
      <documentation>
8
      <documentation>
9
         This extension point allows clients of the EMF Validation
9
         This extension point allows clients of the EMF Validation
10
framework to define &quot;client contexts&quot; that describe the
10
framework to define &quot;client contexts&quot; that describe the
Lines 17-22 Link Here
17
   <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
17
   <include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
18
18
19
   <element name="extension">
19
   <element name="extension">
20
      <annotation>
21
         <appinfo>
22
            <meta.element />
23
         </appinfo>
24
      </annotation>
20
      <complexType>
25
      <complexType>
21
         <sequence>
26
         <sequence>
22
            <element ref="clientContext" minOccurs="0" maxOccurs="unbounded"/>
27
            <element ref="clientContext" minOccurs="0" maxOccurs="unbounded"/>
Lines 41-49 Link Here
41
               <documentation>
46
               <documentation>
42
                  
47
                  
43
               </documentation>
48
               </documentation>
44
               <appInfo>
49
               <appinfo>
45
                  <meta.attribute translatable="true"/>
50
                  <meta.attribute translatable="true"/>
46
               </appInfo>
51
               </appinfo>
47
            </annotation>
52
            </annotation>
48
         </attribute>
53
         </attribute>
49
      </complexType>
54
      </complexType>
Lines 51-59 Link Here
51
56
52
   <element name="clientContext">
57
   <element name="clientContext">
53
      <annotation>
58
      <annotation>
54
         <appInfo>
59
         <appinfo>
55
            <meta.element labelAttribute="id"/>
60
            <meta.element labelAttribute="id"/>
56
         </appInfo>
61
         </appinfo>
57
         <documentation>
62
         <documentation>
58
            &lt;p&gt;
63
            &lt;p&gt;
59
Definition of a client context, representing a class of
64
Definition of a client context, representing a class of
Lines 110-118 Link Here
110
                  Identifies a class implementing the &lt;code&gt;org.eclipse.emf.validation.internal.model.IClientSelector&lt;/code&gt;
115
                  Identifies a class implementing the &lt;code&gt;org.eclipse.emf.validation.internal.model.IClientSelector&lt;/code&gt;
111
internal API interface.
116
internal API interface.
112
               </documentation>
117
               </documentation>
113
               <appInfo>
118
               <appinfo>
114
                  <meta.attribute kind="java" basedOn="org.eclipse.emf.validation.internal.model.IClientSelector"/>
119
                  <meta.attribute kind="java" basedOn="org.eclipse.emf.validation.internal.model.IClientSelector"/>
115
               </appInfo>
120
               </appinfo>
116
            </annotation>
121
            </annotation>
117
         </attribute>
122
         </attribute>
118
      </complexType>
123
      </complexType>
Lines 120-128 Link Here
120
125
121
   <element name="binding">
126
   <element name="binding">
122
      <annotation>
127
      <annotation>
123
         <appInfo>
128
         <appinfo>
124
            <meta.element labelAttribute="context"/>
129
            <meta.element labelAttribute="context"/>
125
         </appInfo>
130
         </appinfo>
126
         <documentation>
131
         <documentation>
127
            &lt;p&gt;
132
            &lt;p&gt;
128
Declares a binding between a client context and one or more
133
Declares a binding between a client context and one or more
Lines 131-136 Link Here
131
&lt;/p&gt;
136
&lt;/p&gt;
132
&lt;p&gt;
137
&lt;p&gt;
133
The constraints to be bound may be specified by either:
138
The constraints to be bound may be specified by either:
139
&lt;/p&gt;
134
&lt;ul&gt;
140
&lt;ul&gt;
135
  &lt;li&gt;the &lt;code&gt;constraint&lt;/code&gt; attribute, to reference
141
  &lt;li&gt;the &lt;code&gt;constraint&lt;/code&gt; attribute, to reference
136
      a single constraint&lt;/li&gt;
142
      a single constraint&lt;/li&gt;
Lines 141-153 Link Here
141
      and/or &lt;code&gt;&amp;lt;category&amp;gt;&lt;/code&gt; elements to
147
      and/or &lt;code&gt;&amp;lt;category&amp;gt;&lt;/code&gt; elements to
142
      reference multiple constraints and/or categories&lt;/li&gt;
148
      reference multiple constraints and/or categories&lt;/li&gt;
143
&lt;/ul&gt;
149
&lt;/ul&gt;
150
&lt;p&gt;
151
Since the 1.3 release, selective exclusion of constraints and sub-categories that are contained by included categories is supported.  Within a &lt;code&gt;&amp;lt;binding&amp;gt;&lt;/code&gt; element, ordering of inclusion and exclusion elements is significant:  they are processed in the order in which they are declared in the extension.  However, the order of inclusions and exclusions in separate bindings for the same context is undefined.
144
&lt;/p&gt;
152
&lt;/p&gt;
145
         </documentation>
153
         </documentation>
146
      </annotation>
154
      </annotation>
147
      <complexType>
155
      <complexType>
148
         <sequence>
156
         <sequence>
149
            <element ref="constraint" minOccurs="0" maxOccurs="unbounded"/>
157
            <choice minOccurs="0" maxOccurs="unbounded">
150
            <element ref="category" minOccurs="0" maxOccurs="unbounded"/>
158
               <element ref="category"/>
159
               <element ref="constraint"/>
160
               <element ref="extendClientContext"/>
161
               <element ref="excludeCategory"/>
162
               <element ref="excludeConstraint"/>
163
            </choice>
151
         </sequence>
164
         </sequence>
152
         <attribute name="context" type="string" use="required">
165
         <attribute name="context" type="string" use="required">
153
            <annotation>
166
            <annotation>
Lines 185-193 Link Here
185
198
186
   <element name="constraint">
199
   <element name="constraint">
187
      <annotation>
200
      <annotation>
188
         <appInfo>
201
         <appinfo>
189
            <meta.element labelAttribute="ref"/>
202
            <meta.element labelAttribute="ref"/>
190
         </appInfo>
203
         </appinfo>
191
         <documentation>
204
         <documentation>
192
            Includes a constraint in a client context
205
            Includes a constraint in a client context
193
&lt;code&gt;&amp;lt;binding&amp;gt;&lt;/code&gt;.
206
&lt;code&gt;&amp;lt;binding&amp;gt;&lt;/code&gt;.
Lines 209-217 Link Here
209
222
210
   <element name="category">
223
   <element name="category">
211
      <annotation>
224
      <annotation>
212
         <appInfo>
225
         <appinfo>
213
            <meta.element labelAttribute="ref"/>
226
            <meta.element labelAttribute="ref"/>
214
         </appInfo>
227
         </appinfo>
215
         <documentation>
228
         <documentation>
216
            Includes a constraint category in a client context
229
            Includes a constraint category in a client context
217
&lt;code&gt;&amp;lt;binding&amp;gt;&lt;/code&gt;.  All of the referenced
230
&lt;code&gt;&amp;lt;binding&amp;gt;&lt;/code&gt;.  All of the referenced
Lines 233-251 Link Here
233
      </complexType>
246
      </complexType>
234
   </element>
247
   </element>
235
248
249
   <element name="extendClientContext">
250
      <annotation>
251
         <documentation>
252
            Since 1.3.  References a client-context that the bound context extends.  Conceptually, this declares that objects matching the referenced context also match my bound context.  In practice, this means that my bound context inherits all of the constraint bindings from the referenced context.
253
&lt;br/&gt;&lt;br/&gt;
254
Of course, subsequent exclusions can filter out unwanted constraints, too.  &lt;b&gt;Note&lt;/b&gt;, also, that this effects a dependency on the referenced client context and also imposes a partial ordering on the bindings.  All of the bindings contributed to the referenced context are applied before any inclusions or exclusions that follow the &lt;code&gt;&amp;lt;extendClientContext&amp;gt;&lt;/code&gt; element in the current &lt;code&gt;&amp;lt;binding&amp;gt;&lt;/code&gt;.
255
         </documentation>
256
      </annotation>
257
      <complexType>
258
         <attribute name="ref" type="string" use="required">
259
            <annotation>
260
               <documentation>
261
                  References the ID of a client-context to extend.  All constraint bindings of the client context are inherited by this binding.
262
               </documentation>
263
            </annotation>
264
         </attribute>
265
      </complexType>
266
   </element>
267
268
   <element name="excludeCategory">
269
      <annotation>
270
         <documentation>
271
            Since 1.3.  Excludes a constraint category from a client context
272
&lt;code&gt;&amp;lt;binding&amp;gt;&lt;/code&gt;.  All of the referenced
273
category&apos;s constraints and those of any sub-categories
274
(recursively) are excluded.  This is useful when including some parent category, to filter out selective sub-categories.  Not only is it simpler than explicitly including all of the desired sub-categories, but it ensures that sub-categories that are added later will be included implicitly.
275
         </documentation>
276
      </annotation>
277
      <complexType>
278
         <attribute name="ref" type="string" use="required">
279
            <annotation>
280
               <documentation>
281
                  References the fully-qualified ID of a constraint category to
282
exclude from the client context. The category ID does not
283
necessarily include its contributing plug-in ID, but is a
284
path reflecting the hierarchical structure of categories.
285
               </documentation>
286
            </annotation>
287
         </attribute>
288
      </complexType>
289
   </element>
290
291
   <element name="excludeConstraint">
292
      <annotation>
293
         <documentation>
294
            Since 1.3.  Excludes a constraint from a client context
295
&lt;code&gt;&amp;lt;binding&amp;gt;&lt;/code&gt;. This is useful when including some parent category, to filter out selective constraints cointained within it.  Not only is it simpler than explicitly including all of the desired constraints and sub-categories, but it ensures that constraints and sub-categories that are added later will be included implicitly.
296
         </documentation>
297
      </annotation>
298
      <complexType>
299
         <attribute name="ref" type="string" use="required">
300
            <annotation>
301
               <documentation>
302
                  References the fully-qualified ID of a constraint to exclude
303
from the client context.  The ID includes the constraint&apos;s
304
contributing plug-in ID, if it is not explicit in the XML
305
definition of the constraint.
306
               </documentation>
307
            </annotation>
308
         </attribute>
309
      </complexType>
310
   </element>
311
236
   <annotation>
312
   <annotation>
237
      <appInfo>
313
      <appinfo>
238
         <meta.section type="since"/>
314
         <meta.section type="since"/>
239
      </appInfo>
315
      </appinfo>
240
      <documentation>
316
      <documentation>
241
         1.0
317
         1.0
242
      </documentation>
318
      </documentation>
243
   </annotation>
319
   </annotation>
244
320
245
   <annotation>
321
   <annotation>
246
      <appInfo>
322
      <appinfo>
247
         <meta.section type="examples"/>
323
         <meta.section type="examples"/>
248
      </appInfo>
324
      </appinfo>
249
      <documentation>
325
      <documentation>
250
         &lt;p&gt;
326
         &lt;p&gt;
251
Example of a context which includes &lt;code&gt;EObjects&lt;/code&gt; in *.library resources only, not
327
Example of a context which includes &lt;code&gt;EObjects&lt;/code&gt; in *.library resources only, not
Lines 291-320 Link Here
291
      </documentation>
367
      </documentation>
292
   </annotation>
368
   </annotation>
293
369
294
   <annotation>
295
      <appInfo>
296
         <meta.section type="apiInfo"/>
297
      </appInfo>
298
      <documentation>
299
         
300
      </documentation>
301
   </annotation>
302
370
303
   <annotation>
304
      <appInfo>
305
         <meta.section type="implementation"/>
306
      </appInfo>
307
      <documentation>
308
         
309
      </documentation>
310
   </annotation>
311
371
312
   <annotation>
372
   <annotation>
313
      <appInfo>
373
      <appinfo>
314
         <meta.section type="copyright"/>
374
         <meta.section type="copyright"/>
315
      </appInfo>
375
      </appinfo>
316
      <documentation>
376
      <documentation>
317
         Copyright (c) 2005  IBM Corporation and others.&lt;br&gt;
377
         Copyright (c) 2005, 2008  IBM Corporation, Zeligsoft Inc., and others.&lt;br&gt;
318
 All rights reserved. This program and the accompanying materials 
378
 All rights reserved. This program and the accompanying materials 
319
 are made available under the terms of the Eclipse Public License v1.0 
379
 are made available under the terms of the Eclipse Public License v1.0 
320
 which accompanies this distribution, and is available at 
380
 which accompanies this distribution, and is available at 
(-)src/org/eclipse/emf/validation/internal/service/impl/tests/AllTests.java (-1 / +4 lines)
Lines 1-7 Link Here
1
/**
1
/**
2
 * <copyright>
2
 * <copyright>
3
 *
3
 *
4
 * Copyright (c) 2003, 2006 IBM Corporation and others.
4
 * Copyright (c) 2003, 2008 IBM Corporation, Zeligsoft Inc., and others.
5
 * All rights reserved.   This program and the accompanying materials
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
7
 * which accompanies this distribution, and is available at
Lines 9-14 Link Here
9
 *
9
 *
10
 * Contributors:
10
 * Contributors:
11
 *   IBM - Initial API and implementation
11
 *   IBM - Initial API and implementation
12
 *   Zeligsoft - Bug 249496
12
 *
13
 *
13
 * </copyright>
14
 * </copyright>
14
 *
15
 *
Lines 43-47 Link Here
43
		
44
		
44
		addTestSuite(BatchValidatorTest.class);
45
		addTestSuite(BatchValidatorTest.class);
45
		addTestSuite(LiveValidatorTest.class);
46
		addTestSuite(LiveValidatorTest.class);
47
		
48
		addTest(ClientContextTest.suite());
46
	}
49
	}
47
}
50
}
(-)plugin.xml (+102 lines)
Lines 470-473 Link Here
470
         </eclass>
470
         </eclass>
471
      </traversalStrategy>
471
      </traversalStrategy>
472
   </extension>
472
   </extension>
473
   
474
   <!-- Constraints only used for client-context inclusion/exclusion testing -->
475
   <extension name="Contraints for client-context testing" point="org.eclipse.emf.validation.constraintProviders">
476
     <category id="clientContextTest" name="JUnit Client Context Testing Context"/>
477
     <category id="clientContextTest/one" name="First level of nesting"/>
478
     <category id="clientContextTest/one/two" name="Second level of nesting"/>
479
     <category id="clientContextTest/one/twoA" name="Second level of nesting (A)"/>
480
     <category id="clientContextTest/one/two/three" name="Third level of nesting"/>
481
     <category id="clientContextTest/one/two/threeA" name="Third level of nesting (A)"/>
482
     <constraintProvider>
483
         <package namespaceUri="http://www.eclipse.org/emf/2002/Ecore" />
484
         <constraints categories="clientContextTest/one">
485
            <constraint name="Dummy1.1" statusCode="1" lang="OCL" id="clientContext.1.1">
486
               <message>Nothing to say.</message>
487
               <target class="EAnnotation"/>
488
               true
489
            </constraint>
490
            <constraint name="Dummy1.2" statusCode="1" lang="OCL" id="clientContext.1.2">
491
               <message>Nothing to say.</message>
492
               <target class="EAnnotation"/>
493
               true
494
            </constraint>
495
         </constraints>
496
         <constraints categories="clientContextTest/one/two">
497
            <constraint name="Dummy2.1" statusCode="1" lang="OCL" id="clientContext.2.1">
498
               <message>Nothing to say.</message>
499
               <target class="EAnnotation"/>
500
               true
501
            </constraint>
502
            <constraint name="Dummy2.2" statusCode="1" lang="OCL" id="clientContext.2.2">
503
               <message>Nothing to say.</message>
504
               <target class="EAnnotation"/>
505
               true
506
            </constraint>
507
         </constraints>
508
         <constraints categories="clientContextTest/one/twoA">
509
            <constraint name="Dummy2a.1" statusCode="1" lang="OCL" id="clientContext.2a.1">
510
               <message>Nothing to say.</message>
511
               <target class="EAnnotation"/>
512
               true
513
            </constraint>
514
            <constraint name="Dummy2a.2" statusCode="1" lang="OCL" id="clientContext.2a.2">
515
               <message>Nothing to say.</message>
516
               <target class="EAnnotation"/>
517
               true
518
            </constraint>
519
         </constraints>
520
         <constraints categories="clientContextTest/one/two/three">
521
            <constraint name="Dummy3.1" statusCode="1" lang="OCL" id="clientContext.3.1">
522
               <message>Nothing to say.</message>
523
               <target class="EAnnotation"/>
524
               true
525
            </constraint>
526
            <constraint name="Dummy3.2" statusCode="1" lang="OCL" id="clientContext.3.2">
527
               <message>Nothing to say.</message>
528
               <target class="EAnnotation"/>
529
               true
530
            </constraint>
531
         </constraints>
532
         <constraints categories="clientContextTest/one/two/threeA">
533
            <constraint name="Dummy3a.1" statusCode="1" lang="OCL" id="clientContext.3a.1">
534
               <message>Nothing to say.</message>
535
               <target class="EAnnotation"/>
536
               true
537
            </constraint>
538
            <constraint name="Dummy3a.2" statusCode="1" lang="OCL" id="clientContext.3a.2">
539
               <message>Nothing to say.</message>
540
               <target class="EAnnotation"/>
541
               true
542
            </constraint>
543
         </constraints>
544
      </constraintProvider>
545
   </extension>
546
   <!-- A client-context only used for inclusion/exclusion testing -->
547
   <extension point="org.eclipse.emf.validation.constraintBindings">
548
      <clientContext
549
            id="org.eclipse.emf.validation.tests.testContextToExtend">
550
          <enablement>
551
            <systemTest property="BOGUS_SYSTEM_PROPERTY" value="1"/>
552
         </enablement>
553
      </clientContext>
554
      <binding context="org.eclipse.emf.validation.tests.testContextToExtend">
555
         <category ref="clientContextTest/one/two/three"/>
556
      </binding>
557
   </extension>
558
   <extension point="org.eclipse.emf.validation.constraintBindings">
559
      <clientContext
560
            id="org.eclipse.emf.validation.tests.testcontext">
561
          <enablement>
562
            <systemTest property="BOGUS_SYSTEM_PROPERTY" value="1"/>
563
         </enablement>
564
      </clientContext>
565
      <binding context="org.eclipse.emf.validation.tests.testcontext">
566
         <category ref="clientContextTest/one"/>
567
         <excludeCategory ref="clientContextTest/one/two"/>
568
         <extendClientContext ref="org.eclipse.emf.validation.tests.testContextToExtend"/>
569
         <excludeConstraint ref="org.eclipse.emf.validation.tests.clientContext.1.1"/>
570
         <excludeConstraint ref="org.eclipse.emf.validation.tests.clientContext.2a.1"/>
571
         <constraint ref="org.eclipse.emf.validation.tests.clientContext.2.2"/>
572
         <constraint ref="org.eclipse.emf.validation.tests.clientContext.3a.2"/>
573
      </binding>
574
   </extension>
473
</plugin>
575
</plugin>
(-)src/org/eclipse/emf/validation/internal/service/impl/tests/ClientContextTest.java (+185 lines)
Added Link Here
1
/**
2
 * <copyright>
3
 * 
4
 * Copyright (c) 2008 Zeligsoft Inc. and others.
5
 * All rights reserved.   This program and the accompanying materials
6
 * are made available under the terms of the Eclipse Public License v1.0
7
 * which accompanies this distribution, and is available at
8
 * http://www.eclipse.org/legal/epl-v10.html
9
 * 
10
 * Contributors:
11
 *   Zeligsoft - Initial API and implementation
12
 * 
13
 * </copyright>
14
 *
15
 * $Id$
16
 */
17
18
package org.eclipse.emf.validation.internal.service.impl.tests;
19
20
import java.util.Collection;
21
22
import junit.framework.Test;
23
import junit.framework.TestCase;
24
import junit.framework.TestSuite;
25
26
import org.eclipse.core.runtime.IStatus;
27
import org.eclipse.core.runtime.Status;
28
import org.eclipse.emf.ecore.EcoreFactory;
29
import org.eclipse.emf.validation.IValidationContext;
30
import org.eclipse.emf.validation.internal.service.ClientContext;
31
import org.eclipse.emf.validation.internal.service.ClientContextManager;
32
import org.eclipse.emf.validation.internal.service.IClientContext;
33
import org.eclipse.emf.validation.model.EvaluationMode;
34
import org.eclipse.emf.validation.model.IModelConstraint;
35
import org.eclipse.emf.validation.service.ConstraintRegistry;
36
import org.eclipse.emf.validation.service.IConstraintDescriptor;
37
import org.eclipse.emf.validation.service.ModelValidationService;
38
39
/**
40
 * Tests the {@link ClientContext} class.
41
 * 
42
 * @author Christian W. Damus (cdamus)
43
 */
44
@SuppressWarnings("nls")
45
public class ClientContextTest
46
		extends TestCase {
47
48
	private IModelConstraint constraint1_1;
49
50
	private IModelConstraint constraint1_2;
51
52
	private IModelConstraint constraint2_1;
53
54
	private IModelConstraint constraint2_2;
55
56
	private IModelConstraint constraint2a_1;
57
58
	private IModelConstraint constraint2a_2;
59
60
	private IModelConstraint constraint3_1;
61
62
	private IModelConstraint constraint3_2;
63
64
	private IModelConstraint constraint3a_1;
65
66
	private IModelConstraint constraint3a_2;
67
68
	private IClientContext fixture;
69
70
	/**
71
	 * Initialize me with my name.
72
	 * 
73
	 * @param name
74
	 *            my name
75
	 */
76
	public ClientContextTest(String name) {
77
		super(name);
78
	}
79
80
	public static Test suite() {
81
		return new TestSuite(ClientContextTest.class, "Client context tests");
82
	}
83
84
	public void test_includedChildOfExcludedCategory() {
85
		assertTrue("Constraint is excluded", fixture.includes(constraint3_1));
86
		assertTrue("Constraint is excluded", fixture.includes(constraint3_2));
87
	}
88
89
	public void test_constraintExcludedFromIncludedCategory() {
90
		assertFalse("Constraint is included", fixture.includes(constraint1_1));
91
		assertTrue("Constraint is excluded", fixture.includes(constraint1_2));
92
	}
93
94
	public void test_constraintIncludedInExcludedCategory() {
95
		assertFalse("Constraint is included", fixture.includes(constraint2_1));
96
		assertTrue("Constraint is excluded", fixture.includes(constraint2_2));
97
	}
98
99
	public void test_constraintExcludedFromIncludedCategory_nested() {
100
		assertFalse("Constraint is included", fixture.includes(constraint2a_1));
101
		assertTrue("Constraint is excluded", fixture.includes(constraint2a_2));
102
	}
103
104
	public void test_constraintIncludedInExcludedCategory_nested() {
105
		assertFalse("Constraint is included", fixture.includes(constraint3a_1));
106
		assertTrue("Constraint is excluded", fixture.includes(constraint3a_2));
107
	}
108
109
	/**
110
	 * Tests that the determination of client-contexts matching an object does
111
	 * not include any that are extended by other matching contexts.
112
	 */
113
	public void test_multipleMatchingContextsWithExclusions() {
114
		Collection<IClientContext> contexts;
115
116
		System.setProperty("BOGUS_SYSTEM_PROPERTY", "1");
117
		try {
118
			contexts = ClientContextManager.getInstance().getClientContextsFor(
119
				EcoreFactory.eINSTANCE.createEAnnotation());
120
		} finally {
121
			System.clearProperty("BOGUS_SYSTEM_PROPERTY");
122
		}
123
124
		boolean extenderFound = false;
125
		boolean extendedFound = false;
126
		
127
		for (IClientContext next : contexts) {
128
			extenderFound |= "org.eclipse.emf.validation.tests.testcontext".equals(next.getId());
129
			extendedFound |= "org.eclipse.emf.validation.tests.testContextToExtend".equals(next.getId());
130
		}
131
		
132
		assertTrue("Extending context not matched", extenderFound);
133
		assertFalse("Extended context was matched", extendedFound);
134
	}
135
136
	//
137
	// Test framework
138
	//
139
140
	@Override
141
	protected void setUp()
142
			throws Exception {
143
144
		super.setUp();
145
146
		fixture = ClientContextManager.getInstance().getClientContext(
147
			"org.eclipse.emf.validation.tests.testcontext");
148
149
		final String prefix = "org.eclipse.emf.validation.tests.clientContext.";
150
		final ConstraintRegistry reg = ConstraintRegistry.getInstance();
151
152
		// cause our test constraints to be created
153
		ModelValidationService.getInstance().newValidator(EvaluationMode.BATCH)
154
			.validate(EcoreFactory.eINSTANCE.createEAnnotation());
155
156
		constraint1_1 = new TestConstraint(reg.getDescriptor(prefix + "1.1"));
157
		constraint1_2 = new TestConstraint(reg.getDescriptor(prefix + "1.2"));
158
		constraint2_1 = new TestConstraint(reg.getDescriptor(prefix + "2.1"));
159
		constraint2_2 = new TestConstraint(reg.getDescriptor(prefix + "2.2"));
160
		constraint2a_1 = new TestConstraint(reg.getDescriptor(prefix + "2a.1"));
161
		constraint2a_2 = new TestConstraint(reg.getDescriptor(prefix + "2a.2"));
162
		constraint3_1 = new TestConstraint(reg.getDescriptor(prefix + "3.1"));
163
		constraint3_2 = new TestConstraint(reg.getDescriptor(prefix + "3.2"));
164
		constraint3a_1 = new TestConstraint(reg.getDescriptor(prefix + "3a.1"));
165
		constraint3a_2 = new TestConstraint(reg.getDescriptor(prefix + "3a.2"));
166
	}
167
168
	private static final class TestConstraint
169
			implements IModelConstraint {
170
171
		private IConstraintDescriptor desc;
172
173
		TestConstraint(IConstraintDescriptor desc) {
174
			this.desc = desc;
175
		}
176
177
		public IStatus validate(IValidationContext c) {
178
			return Status.OK_STATUS;
179
		}
180
181
		public IConstraintDescriptor getDescriptor() {
182
			return desc;
183
		}
184
	}
185
}

Return to bug 249496