blob: 617a7dc87bb54c0f3d5a89717c76fdf319e670df [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2014-2015 itemis and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* itemis - Initial API and implementation
* itemis - [463895] org.eclipse.sphinx.emf.check.AbstractCheckValidator.validate(EClass, EObject, DiagnosticChain, Map<Object, Object>) throws NPE
* itemis - [473260] Progress indication of check framework
* itemis - [473261] Check Validation: Cancel button unresponsive
*
* </copyright>
*/
package org.eclipse.sphinx.emf.check.internal;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.emf.common.util.EList;
import org.eclipse.sphinx.emf.check.Check;
import org.eclipse.sphinx.emf.check.CheckValidatorRegistry;
import org.eclipse.sphinx.emf.check.CheckValidatorState;
import org.eclipse.sphinx.emf.check.ICheckValidator;
import org.eclipse.sphinx.emf.check.catalog.Catalog;
import org.eclipse.sphinx.emf.check.catalog.Category;
public class CheckMethodWrapper {
private Method method;
private Check checkAnnotation;
private ICheckValidator validator;
private CheckValidatorRegistry checkValidatorRegistry;
public CheckMethodWrapper(ICheckValidator validator, Method method, CheckValidatorRegistry checkValidatorRegistry) {
Assert.isNotNull(validator);
Assert.isNotNull(method);
Assert.isNotNull(checkValidatorRegistry);
Assert.isNotNull(method.getAnnotation(Check.class));
this.validator = validator;
this.method = method;
checkAnnotation = method.getAnnotation(Check.class);
this.checkValidatorRegistry = checkValidatorRegistry;
}
public ICheckValidator getValidator() {
return validator;
}
public Method getMethod() {
return method;
}
public String getAnnotatedConstraint() {
return checkAnnotation.constraint();
}
public Set<String> getAnnotatedCategories() {
String[] categories = checkAnnotation.categories();
if (categories.length > 0) {
// Ignore isolate empty categories
if (categories.length > 1 || !categories[0].isEmpty()) {
return new HashSet<String>(Arrays.asList(categories));
}
}
return Collections.emptySet();
}
private boolean isOtherCategorySelected(Set<String> selectedCategories) {
Assert.isNotNull(selectedCategories);
for (String categoryId : selectedCategories) {
if (categoryId.equals(ICheckValidator.OPTION_CATEGORIES_OTHER_ID)) {
return true;
}
}
return false;
}
public void invoke(CheckValidatorState state, Set<String> selectedCategories) throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
if (validator.getState().get() != null && validator.getState().get() != state) {
throw new IllegalStateException("State is already assigned."); //$NON-NLS-1$
}
boolean wasNull = validator.getState().get() == null;
if (wasNull) {
validator.getState().set(state);
}
try {
if (!state.checkValidationMode.shouldCheck(checkAnnotation.value())) {
return;
}
if (selectedCategories.isEmpty()) {
// Invoke the validation using all existing categories if no categories are selected
invokeInternal(state);
} else {
Set<String> categories = new HashSet<String>();
categories.addAll(selectedCategories);
Set<String> annotatedCategories = getAnnotatedCategories();
Catalog catalog = checkValidatorRegistry.getCheckCatalog(validator);
// If no categories are specified in the check method's @Check annotation, invoke the check method on
// all categories as per the underlying constraint in the check catalog; otherwise invoke the check
// method on the intersection of categories provided by the user, and the categories defined in the
// check catalog.
// Case 1: Only @Check annotation without constraint
if (getAnnotatedConstraint().isEmpty()) {
if (isOtherCategorySelected(selectedCategories)) {
invokeInternal(state);
}
}
// Case 2: @Check annotation with a constraint and without any category
else if (annotatedCategories.isEmpty()) {
if (catalog != null && !catalog.getCategories().isEmpty()) {
retainAll(categories, catalog.getCategories());
// Go ahead if scope is not empty
if (!categories.isEmpty()) {
invokeInternal(state);
}
}
}
// Case 3: @Check annotation with a constraint and categories
else {
// Make intersection with annotated categories
categories.retainAll(annotatedCategories);
// Make intersection with categories associated with this validator in check catalog
if (catalog != null && !catalog.getCategories().isEmpty()) {
retainAll(categories, catalog.getCategories());
}
// Go ahead if scope is not empty
if (!categories.isEmpty()) {
invokeInternal(state);
}
}
}
} finally {
if (wasNull) {
validator.getState().set(null);
}
}
}
protected void invokeInternal(CheckValidatorState state) throws IllegalAccessException, InvocationTargetException {
state.currentMethod = method;
state.currentCheckType = checkAnnotation.value();
state.constraint = getAnnotatedConstraint();
method.setAccessible(true);
method.invoke(validator, state.currentObject);
}
private void retainAll(Set<String> categories, EList<Category> categoryList) {
Set<String> categoryIDs = new HashSet<String>();
for (Category category : categoryList) {
categoryIDs.add(category.getId());
}
categories.retainAll(categoryIDs);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
CheckMethodWrapper other = (CheckMethodWrapper) obj;
if (!method.equals(other.method)) {
return false;
}
if (!validator.equals(other.validator)) {
return false;
}
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + method.hashCode();
result = prime * result + validator.hashCode();
return result;
}
@Override
public String toString() {
return "CheckMethodWrapper [method=" + method + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
}