blob: c5d70259710cdbb8023745d0b183e754c8b31c97 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012-2014 SAP SE.
* 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:
* SAP SE - initial API and implementation and/or initial documentation
*
*******************************************************************************/
package org.eclipse.ogee.model.api.impl;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.validation.model.EvaluationMode;
import org.eclipse.emf.validation.service.IBatchValidator;
import org.eclipse.emf.validation.service.IConstraintDescriptor;
import org.eclipse.emf.validation.service.IConstraintFilter;
import org.eclipse.emf.validation.service.ModelValidationService;
import org.eclipse.ogee.model.api.Activator;
import org.eclipse.ogee.model.api.IValidator;
import org.eclipse.ogee.model.odata.Association;
import org.eclipse.ogee.model.odata.ComplexType;
import org.eclipse.ogee.model.odata.EDMXSet;
import org.eclipse.ogee.model.odata.EntitySet;
import org.eclipse.ogee.model.odata.EntityType;
import org.eclipse.ogee.model.odata.NavigationProperty;
import org.eclipse.ogee.model.odata.Property;
public class Validator implements IValidator {
/**
* Name constraint IDs
*/
private static final String COMPLEX_TYPE_NAME_CONSTRAINT = "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.ComplexTypeNameConstraint"; //$NON-NLS-1$
private static final String ENTITY_TYPE_NAME_CONSTRAINT = "EntityTypeNameConstraint"; //$NON-NLS-1$
private static final String ENTITY_SET_NAME_CONSTRAINT = "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.EntitySetNameConstraint"; //$NON-NLS-1$
private static final String ASSOCIATION_NAME_CONSTRAINT = "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.AssociationNameConstraint"; //$NON-NLS-1$
// private static final String ASSOCIATION_SET_NAME_CONSTRAINT =
// "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.AssociationSetNameConstraint";
// private static final String ENTITY_CONTAINER_NAME_CONSTRAINT =
// "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.EntityContainerNameConstraint";
// private static final String FUNCTION_NAME_CONSTRAINT =
// "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.FunctionNameConstraint";
private static final String NAVIGATION_PROPERTY_NAME_CONSTRAINT = "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.NavigationPropertyNameConstraint"; //$NON-NLS-1$
private static final String PROPERTY_NAME_CONSTRAINT = "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.PropertyNameConstraint"; //$NON-NLS-1$
// private static final String PARAMETER_NAME_CONSTRAINT =
// "org.eclispe.ogee.model.validation.org.eclispe.ogee.model.ParameterNameConstraint";
/**
* EMF Name Feature
*/
private static final String EMF_NAME_FEATURE = "name"; //$NON-NLS-1$
private static final String EMF_ALIAS_FEATURE = "alias"; //$NON-NLS-1$
/**
* Message Keys
**/
private static final String ENTITY_TYPE_NAME_NOT_INITIAL_MSG = "EntityType#name#1"; //$NON-NLS-1$
private static final String COMPLEX_TYPE_NAME_NOT_INITIAL_MSG = "ComplexType#name#1"; //$NON-NLS-1$
private static final String PROPERTY_NAME_NOT_INITIAL_MSG = "Property#name#1"; //$NON-NLS-1$
private static final String PROPERTY_TYPE_NOT_INITIAL_MSG = "Property#type#1"; //$NON-NLS-1$
private static final String ENTITY_CONTAINER_NAME_NOT_INITIAL_MSG = "EntityContainer#name#1"; //$NON-NLS-1$
private static final String ASSOCIATION_NAME_NOT_INITIAL_MSG = "Association#name#1"; //$NON-NLS-1$
private static final String NAVIGATION_PROPERTY_NAME_NOT_INITIAL_MSG = "NavigationProperty#name#1"; //$NON-NLS-1$
private static final String NAVIGATION_PROPERTY_RELATIONSHIP_NOT_INITIAL_MSG = "NavigationProperty#relationship#1"; //$NON-NLS-1$
private static final String NAVIGATION_PROPERTY_FROMROLE_NOT_INITIAL_MSG = "NavigationProperty#fromRole#1"; //$NON-NLS-1$
private static final String NAVIGATION_PROPERTY_TOROLE_NOT_INITIAL_MSG = "NavigationProperty#toRole#1"; //$NON-NLS-1$
private static final String FUNCTION_IMPORT_NAME_NOT_INITIAL_MSG = "FunctionImport#name#1"; //$NON-NLS-1$
private static final String PARAMETER_NAME_NOT_INITIAL_MSG = "Parameter#name#1"; //$NON-NLS-1$
private static final String PARAMETER_TYPE_NOT_INITIAL_MSG = "Parameter#type#1"; //$NON-NLS-1$
private static final String ENTITY_SET_NAME_NOT_INITIAL_MSG = "EntitySet#name#1"; //$NON-NLS-1$
private static final String ENTITY_SET_TYPE_NOT_INITIAL_MSG = "EntitySet#type#1"; //$NON-NLS-1$
private static final String ASSOCIATION_SET_NAME_NOT_INITIAL_MSG = "AssociationSet#name#1"; //$NON-NLS-1$
private static final String ASSOCIATION_SET_ASSOCIATION_NOT_INITIAL_MSG = "AssociationSet#association#1"; //$NON-NLS-1$
private static final String ROLE_NAME_INITIAL_MSG = "Role#name#1"; //$NON-NLS-1$
private static final String ROLE_MULTIPLICITY_NOT_INITIAL_MSG = "Role#multiplicity#1"; //$NON-NLS-1$
private static final String ROLE_TYPE_NOT_INITIAL_MSG = "Role#type#1"; //$NON-NLS-1$
private static final String ASSOCIATION_SET_END_ROLE_NOT_INITIAL_MSG = "AssociationSetEnd#Role#1"; //$NON-NLS-1$
private static final String ASSOCIATION_SET_END_ENTITY_SET_NOT_INITIAL_MSG = "AssociationSetEnd#entitySet#1"; //$NON-NLS-1$
private static final String EDMX_DATASERVICE_NOT_INITIAL_MSG = "EDMX#dataService#1"; //$NON-NLS-1$
private static final String REFERENTIAL_CONSTRAINT_DEPENDENT_NOT_INITIAL_MSG = "ReferentialConstraint#dependent#1"; //$NON-NLS-1$
private static final String REFERENTIAL_CONSTRAINT_PRINCIPAL_NOT_INITIAL_MSG = "ReferentialConstraint#principal#1"; //$NON-NLS-1$
private static final String REFERENTIAL_CONSTRAINT_KEYMAPPINGS_MUST_EXIST_MSG = "ReferentialConstraint#keyMappings#1"; //$NON-NLS-1$
private static final String PROPERTY_MAPPING_DEPENDENTKEY_MUST_EXIST_MSG = "PropertyMapping#dependentKeys#1"; //$NON-NLS-1$
private static final String PROPERTY_MAPPING_PRINCIPALKEY_MUST_EXIST_MSG = "PropertyMapping#principalKeys#1"; //$NON-NLS-1$
private static final String PROPERTY_MAPPING_VALUE_MUST_EXIST_MSG = "PropertyMapping#value#1"; //$NON-NLS-1$
private static final String SIMPLE_TYPE_TYPE_NOT_INITIAL_MSG = "SimpleType#type#1"; //$NON-NLS-1$
private static final String BINDING_TYPE_NOT_INITIAL_MSG = "Binding#type#1"; //$NON-NLS-1$
private static final String DATA_SERVICE_VERSION_NOT_INITIAL_MSG = "DataService#version#1"; //$NON-NLS-1$
private static final String COMPLEX_TYPE_USAGE_TYPE_NOT_INITIAL_MSG = "ComplexTypeUsage#complexType#1"; //$NON-NLS-1$
private static final String RETURN_ENTITY_TYPE_USAGE_ENTITY_TYPE_NOT_INITIAL_MSG = "ReturnEntityTypeUsage#entityType#1"; //$NON-NLS-1$
private static final String ENUMTYPE_NAME_NOT_INITIAL_MSG = "EnumType#name#1"; //$NON-NLS-1$
private static final String ENUMMEMBER_NAME_NOT_INITIAL_MSG = "EnumMember#name#1"; //$NON-NLS-1$
private static final String ENUMTYPE_USAGE_ENUMTYPE_NOT_INITIAL_MSG = "EnumTypeUsage#enumType#1"; //$NON-NLS-1$
private static final String VALUE_ANNOTATION_TARGET_NOT_INITIAL_MSG = "ValueAnnotation#target#1"; //$NON-NLS-1$
private static final String USING_USED_NAMESPACE_NOT_INITIAL_MSG = "Using#usedNamespace#1"; //$NON-NLS-1$
private Map<String, String> messages;
public Validator() {
this.messages = new HashMap<String, String>();
this.messages.put(ENTITY_TYPE_NAME_NOT_INITIAL_MSG,
Messages.Validator_EntityType_NameNotInitial);
this.messages.put(COMPLEX_TYPE_NAME_NOT_INITIAL_MSG,
Messages.Validator_ComplexType_NameNotInitial);
this.messages.put(PROPERTY_NAME_NOT_INITIAL_MSG,
Messages.Validator_Property_NameNotInitial);
this.messages.put(PROPERTY_TYPE_NOT_INITIAL_MSG,
Messages.Validator_Property_TypeNotInitial);
this.messages.put(ENTITY_CONTAINER_NAME_NOT_INITIAL_MSG,
Messages.Validator_EntityContainer_NameNotInitial);
this.messages.put(ASSOCIATION_NAME_NOT_INITIAL_MSG,
Messages.Validator_Association_NameNotInitial);
this.messages.put(NAVIGATION_PROPERTY_NAME_NOT_INITIAL_MSG,
Messages.Validator_NavigationProperty_NameNotInitial);
this.messages.put(NAVIGATION_PROPERTY_RELATIONSHIP_NOT_INITIAL_MSG,
Messages.Validator_NavigationProperty_RelationshipNotInitial);
this.messages.put(NAVIGATION_PROPERTY_FROMROLE_NOT_INITIAL_MSG,
Messages.Validator_NavigationProperty_FromRoleNotInitial);
this.messages.put(NAVIGATION_PROPERTY_TOROLE_NOT_INITIAL_MSG,
Messages.Validator_NavigationProperty_ToRoleNotInitial);
this.messages.put(FUNCTION_IMPORT_NAME_NOT_INITIAL_MSG,
Messages.Validator_FunctionImport_NameNotInitial);
this.messages.put(PARAMETER_NAME_NOT_INITIAL_MSG,
Messages.Validator_Parameter_NameNotInitial);
this.messages.put(PARAMETER_TYPE_NOT_INITIAL_MSG,
Messages.Validator_Parameter_TypeNotInitial);
this.messages.put(ENTITY_SET_NAME_NOT_INITIAL_MSG,
Messages.Validator_EntitySet_NameNotInitial);
this.messages.put(ENTITY_SET_TYPE_NOT_INITIAL_MSG,
Messages.Validator_EntitySet_TypeNotInitial);
this.messages.put(ASSOCIATION_SET_NAME_NOT_INITIAL_MSG,
Messages.Validator_AssociationSet_NameNotInitial);
this.messages.put(ASSOCIATION_SET_ASSOCIATION_NOT_INITIAL_MSG,
Messages.Validator_AssociationSet_AssociationNotInitial);
this.messages.put(ROLE_NAME_INITIAL_MSG,
Messages.Validator_Role_NameNotInitial);
this.messages.put(ROLE_MULTIPLICITY_NOT_INITIAL_MSG,
Messages.Validator_Role_MultiplicityNotInitial);
this.messages.put(ROLE_TYPE_NOT_INITIAL_MSG,
Messages.Validator_Role_TypeNotInitial);
this.messages.put(ASSOCIATION_SET_END_ROLE_NOT_INITIAL_MSG,
Messages.Validator_AssociationSetEnd_RoleNotInitial);
this.messages.put(ASSOCIATION_SET_END_ENTITY_SET_NOT_INITIAL_MSG,
Messages.Validator_AssociationSetEnd_EntitySetNotInitial);
this.messages.put(EDMX_DATASERVICE_NOT_INITIAL_MSG,
Messages.Validator_EDMX_DataServiceNotInitial);
this.messages
.put(PROPERTY_MAPPING_DEPENDENTKEY_MUST_EXIST_MSG,
Messages.Validator_PropertyMapping_DependentKeyPropertyMustExist);
this.messages
.put(PROPERTY_MAPPING_PRINCIPALKEY_MUST_EXIST_MSG,
Messages.Validator_PropertyMapping_PrincipalKeyPropertyMustExist);
this.messages
.put(REFERENTIAL_CONSTRAINT_DEPENDENT_NOT_INITIAL_MSG,
Messages.Validator_ReferentialConstraint_DependentRoleNotInitial);
this.messages
.put(REFERENTIAL_CONSTRAINT_PRINCIPAL_NOT_INITIAL_MSG,
Messages.Validator_ReferentialConstraint_PrincipalRoleNotInitial);
this.messages.put(REFERENTIAL_CONSTRAINT_KEYMAPPINGS_MUST_EXIST_MSG,
Messages.Validator_ReferentialConstraint_KeyMappingsMustExist);
this.messages.put(PROPERTY_MAPPING_VALUE_MUST_EXIST_MSG,
Messages.Validator_PropertyMapping_ValueMustExist);
this.messages.put(SIMPLE_TYPE_TYPE_NOT_INITIAL_MSG,
Messages.Validator_SimpleType_TypeNotInitial);
this.messages.put(BINDING_TYPE_NOT_INITIAL_MSG,
Messages.Validator_Binding_TypeNotInitial);
this.messages.put(DATA_SERVICE_VERSION_NOT_INITIAL_MSG,
Messages.Validator_DataService_VersionNotInitial);
this.messages.put(COMPLEX_TYPE_USAGE_TYPE_NOT_INITIAL_MSG,
Messages.Validator_ComplexTypeUsage_TypeNotInitial);
this.messages.put(RETURN_ENTITY_TYPE_USAGE_ENTITY_TYPE_NOT_INITIAL_MSG,
Messages.Validator_ReturnEntityTypeUsage_EntityTypeNotInitial);
this.messages.put(ENUMTYPE_NAME_NOT_INITIAL_MSG,
Messages.Validator_EnumType_NameNotInitial);
this.messages.put(ENUMMEMBER_NAME_NOT_INITIAL_MSG,
Messages.Validator_EnumMember_NameNotInitial);
this.messages.put(ENUMTYPE_USAGE_ENUMTYPE_NOT_INITIAL_MSG,
Messages.Validator_EnumTypeUsage_EnumTypeNotInitial);
this.messages.put(VALUE_ANNOTATION_TARGET_NOT_INITIAL_MSG,
Messages.Validator_ValueAnnotation_TargetNotInitial);
this.messages.put(USING_USED_NAMESPACE_NOT_INITIAL_MSG,
Messages.Validator_Using_UsedNamespaceNotInitial);
}
@Override
public Diagnostic validate(EDMXSet edmxSet) {
Diagnostic result;
IResource resource = getResourceFromEObject(edmxSet);
Diagnostic diagnostic = Diagnostician.INSTANCE.validate(edmxSet);
// Cleanup markers first
if (resource != null) {
try {
resource.deleteMarkers(Activator.problemMarkerId, false,
IResource.DEPTH_ZERO);
} catch (CoreException e1) {
e1.printStackTrace();
}
}
List<Diagnostic> results = diagnostic.getChildren();
// Create human readable result messages
List<Diagnostic> improvedResults = calculateImprovedDiagnostics(results);
// Create new markers
if (resource != null) {
Iterator<Diagnostic> iter = improvedResults.iterator();
while (iter.hasNext()) {
result = iter.next();
try {
addIMarker(result, resource);
} catch (CoreException e) {
e.printStackTrace();
}
}
}
return diagnostic;
}
@Override
public IStatus isValidName(EntityType entityType) {
return isValidName(entityType, ENTITY_TYPE_NAME_CONSTRAINT);
}
@Override
public IStatus isValidName(ComplexType complexType) {
return isValidName(complexType, COMPLEX_TYPE_NAME_CONSTRAINT);
}
@Override
public IStatus isValidName(Association association) {
return isValidName(association, ASSOCIATION_NAME_CONSTRAINT);
}
@Override
public IStatus isValidName(EntitySet entitySet) {
return isValidName(entitySet, ENTITY_SET_NAME_CONSTRAINT);
}
@Override
public IStatus isValidName(NavigationProperty navigationProperty) {
return isValidName(navigationProperty,
NAVIGATION_PROPERTY_NAME_CONSTRAINT);
}
@Override
public IStatus isValidName(Property property) {
return isValidName(property, PROPERTY_NAME_CONSTRAINT);
}
private IStatus isValidName(EObject eObject, String constraintId) {
final String validationConstraintId = constraintId;
// Ensure that all constraints are loaded
ModelValidationService.getInstance().loadXmlConstraintDeclarations();
// Receive an EMF validator instance
IBatchValidator batchValidator = ModelValidationService.getInstance()
.newValidator(EvaluationMode.BATCH);
// Also include live constraints
batchValidator.setIncludeLiveConstraints(true);
// Only validate the given constraint
batchValidator.addConstraintFilter(new IConstraintFilter() {
@Override
public boolean accept(IConstraintDescriptor constraint,
EObject target) {
return constraint.getId().equals(validationConstraintId);
}
});
// Invoke the validation on the desired target object
IStatus status = batchValidator.validate(eObject);
return status;
}
private IResource getResourceFromEObject(EObject eObject) {
IResource res = null;
Resource eResource = eObject.eResource();
if (eResource != null) {
URI eUri = eResource.getURI();
if (eUri.isPlatformResource()) {
String platformString = eUri.toPlatformString(true);
res = ResourcesPlugin.getWorkspace().getRoot()
.findMember(platformString);
}
}
return res;
}
private void addIMarker(Diagnostic diagnostic, IResource resource)
throws CoreException {
if (diagnostic.getData() == null || diagnostic.getData().size() == 0) {
return;
}
EObject eObject = (EObject) diagnostic.getData().get(0);
if (eObject == null) {
return;
}
String uriString = EcoreUtil.getURI(eObject).toString();
IMarker marker = resource.createMarker(Activator.problemMarkerId);
Map<String, Object> attributes = new HashMap<String, Object>();
// To throw user readable error message in case of duplicate schema
// namespace
if (diagnostic.getMessage().contains("schemata")
&& diagnostic.getMessage().contains("namespace")
&& diagnostic.getMessage().contains("collides")) {
attributes.put(IMarker.MESSAGE,
Messages.Validator_Using_DuplicateNamespace);
attributes.put(IMarker.SOURCE_ID, uriString);
attributes.put(IMarker.LOCATION, uriString);
} else {
attributes.put(IMarker.MESSAGE, diagnostic.getMessage());
attributes.put(IMarker.SOURCE_ID, uriString);
attributes.put(IMarker.LOCATION, uriString);
}
// Mapping the severity between Diagnostic and Problem Markers
if (diagnostic.getSeverity() == Diagnostic.ERROR) {
attributes.put(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
attributes.put(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
} else if (diagnostic.getSeverity() == Diagnostic.WARNING) {
attributes.put(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
attributes.put(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL);
} else if (diagnostic.getSeverity() == Diagnostic.INFO) {
attributes.put(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
attributes.put(IMarker.PRIORITY, IMarker.PRIORITY_LOW);
}
marker.setAttributes(attributes);
}
private List<Diagnostic> calculateImprovedDiagnostics(
List<Diagnostic> diagnostics) {
Iterator<Diagnostic> iterator = diagnostics.iterator();
List<Diagnostic> improvedDiagnostics = new LinkedList<Diagnostic>();
Diagnostic improvedDiagnostic;
EObject eObject;
EStructuralFeature feature;
EAttribute nameAttribute;
while (iterator.hasNext()) {
Diagnostic diagnostic = iterator.next();
Object[] object = diagnostic.getData().toArray();
eObject = null;
feature = null;
if (object.length == 2) {
if (object[0] instanceof EObject) {
eObject = (EObject) object[0];
feature = (EStructuralFeature) object[1];
}
}
String codeString = null;
if (eObject != null && feature != null) {
codeString = eObject.eClass().getName()
+ "#" + feature.getName() + "#" + diagnostic.getCode(); //$NON-NLS-1$ //$NON-NLS-2$
}
if (this.messages.containsKey(codeString)) {
Iterator<EAttribute> attributeIterator = eObject.eClass()
.getEAllAttributes().iterator();
nameAttribute = null;
while (attributeIterator.hasNext()) {
EAttribute eAttribute = attributeIterator.next();
if (eAttribute.getName() != null
&& eAttribute.getName().equals(EMF_NAME_FEATURE)) {
nameAttribute = eAttribute;
} else if (eAttribute.getName() != null
&& eAttribute.getName().equals(EMF_ALIAS_FEATURE)) {
nameAttribute = eAttribute;
}
}
if (nameAttribute != null) {
improvedDiagnostic = new BasicDiagnostic(
diagnostic.getSeverity(), diagnostic.getSource(),
diagnostic.getCode(), Messages.bind(
this.messages.get(codeString),
eObject.eGet(nameAttribute)), diagnostic
.getData().toArray());
} else {
improvedDiagnostic = new BasicDiagnostic(
diagnostic.getSeverity(), diagnostic.getSource(),
diagnostic.getCode(),
this.messages.get(codeString), diagnostic.getData()
.toArray());
}
improvedDiagnostics.add(improvedDiagnostic);
} else {
improvedDiagnostics.add(diagnostic);
}
}
return improvedDiagnostics;
}
}