blob: 6f55c1ed91cbd0852066e88551af9284194794ca [file] [log] [blame]
/**
* Copyright (c) 2011, 2015 - Lunifera GmbH (Gross Enzersdorf, Austria), Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
* 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:
* Florian Pirchner - Initial implementation
*/
/*
* generated by Xtext
*/
package org.eclipse.osbp.dsl.dto.xtext.validation;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.xtext.common.types.JvmGenericType;
import org.eclipse.xtext.common.types.util.TypeReferences;
import org.eclipse.xtext.naming.IQualifiedNameProvider;
import org.eclipse.xtext.validation.Check;
import org.eclipse.xtext.validation.CheckType;
import org.eclipse.xtext.validation.ValidationMessageAcceptor;
import org.eclipse.xtext.xbase.lib.Extension;
import org.eclipse.osbp.dsl.dto.xtext.extensions.DtoModelExtensions;
import org.eclipse.osbp.dsl.semantic.common.types.LDataType;
import org.eclipse.osbp.dsl.semantic.common.types.LFeature;
import org.eclipse.osbp.dsl.semantic.common.types.LPackage;
import org.eclipse.osbp.dsl.semantic.common.types.LType;
import org.eclipse.osbp.dsl.semantic.common.types.LTypedPackage;
import org.eclipse.osbp.dsl.semantic.common.types.OSBPTypesPackage;
import org.eclipse.osbp.dsl.semantic.dto.LDto;
import org.eclipse.osbp.dsl.semantic.dto.LDtoAttribute;
import org.eclipse.osbp.dsl.semantic.dto.LDtoFeature;
import org.eclipse.osbp.dsl.semantic.dto.LDtoInheritedAttribute;
import org.eclipse.osbp.dsl.semantic.dto.LDtoInheritedReference;
import org.eclipse.osbp.dsl.semantic.dto.LDtoModel;
import org.eclipse.osbp.dsl.semantic.dto.LDtoReference;
import org.eclipse.osbp.dsl.semantic.dto.OSBPDtoPackage;
import com.google.inject.Inject;
/**
* Custom validation rules.
*
* see http://www.eclipse.org/Xtext/documentation.html#validation
*/
@SuppressWarnings("restriction")
public class DtoGrammarJavaValidator extends
org.eclipse.osbp.dsl.dto.xtext.validation.AbstractDtoGrammarJavaValidator {
private static final String CODE__MISSING_OPPOSITE_REFERENCE = "104";
private static final String CODE__BIDIRECTIONAL_CASCADE_INVALID = "105";
private static final String CODE__CASCADE_DIRECTION_INVALID = "106";
private static final String CODE__OPPOSITE_WITHOUT_CASCADE = "107";
private static final String CODE__UUID_WRONG_TYPE = "108";
private static final String CODE__TWO_OPPOSITES_REQUIRED = "109";
private static final String CODE__DUPLICATE_ID = "110";
private static final String CODE__DUPLICATE_VERSION = "111";
private static final String CODE__DUPLICATE_PROPERTY_NAME = "112";
private static final String CODE__DUPLICATE_DOMAIN_KEY = "113";
private static final String CODE__DUPLICATE_DOMAIN_DESCRIPTION = "114";
private static final String CODE__DOMAIN_KEY__NO_MANY = "115";
private static final String CODE__DOMAIN_DESCRIPTION__NO_MANY = "116";
private static final String CODE__DOMAIN_KEY__TYPE = "117";
private static final String CODE__DOMAIN_DESCRIPTION__TYPE = "118";
private static final String CODE__DUPLICATE_DIRTY = "119";
private static final String CODE__DIRT__NO_MANY = "120";
private static final String CODE__DIRT__TYPE = "121";
@Inject
private IQualifiedNameProvider qnp;
@Inject
private DtoModelExtensions extensions;
@Check
public void checkDatatype_asPrimitive(LDataType dt) {
super.checkDatatype_asPrimitive(dt);
}
@Check
public void checkMulti_HasOppositeReference(LDtoReference prop) {
if (prop.isCascading()) {
if (extensions.isToMany(prop) && prop.getOpposite() == null) {
error("A cascading 'to-many' association needs an opposite reference.",
OSBPDtoPackage.Literals.LDTO_REFERENCE__OPPOSITE,
ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
CODE__MISSING_OPPOSITE_REFERENCE, (String[]) null);
}
}
}
@Check
public void checkOpposite_NotAlsoCascading(LDtoReference prop) {
if (prop.getOpposite() != null) {
if (prop.isCascading() && prop.getOpposite().isCascading()) {
error("Only one opposite may be specified as cascade",
OSBPTypesPackage.Literals.LREFERENCE__CASCADING,
CODE__BIDIRECTIONAL_CASCADE_INVALID, (String[]) null);
}
if (extensions.isToMany(prop.getOpposite())) {
if (prop.isCascading()) {
error("Cascade must not affect the common parent in a many-to-one relation",
prop,
OSBPTypesPackage.Literals.LREFERENCE__CASCADING,
CODE__CASCADE_DIRECTION_INVALID, new String[0]);
}
}
}
}
@Check
public void checkOpposite_TwoOpposites(LDtoReference prop) {
if (prop.getOpposite() != null
&& prop.getOpposite().getOpposite() == null) {
error("Both references need to have an opposite.",
OSBPDtoPackage.Literals.LDTO_REFERENCE__OPPOSITE,
CODE__TWO_OPPOSITES_REQUIRED, (String[]) null);
}
}
@Check
public void checkOpposite_OneIsCascading(LDtoReference prop) {
// Bounds propBound = extensions.getBounds(prop);
//
// if (prop.getOpposite() != null) {
// Bounds oppositeBound = extensions.getBounds(prop.getOpposite());
//
// if (propBound.isToMany() || oppositeBound.isToMany()) {
// // no check required!
// // return;
// }
// }
if (prop.getOpposite() != null) {
if (!prop.isCascading() && !prop.getOpposite().isCascading()) {
error("Opposite references may only defined for cascading relations.",
prop, OSBPTypesPackage.Literals.LREFERENCE__CASCADING,
CODE__OPPOSITE_WITHOUT_CASCADE, new String[0]);
}
}
}
@Check
public void checkProperties_JavaKeyWord(LFeature lprop) {
super.checkProperties_JavaKeyWord(lprop);
}
@Check
public void checkDuplicatePackages_InFile(LDtoModel lmodel) {
Set<String> names = new HashSet<String>();
int counter = -1;
for (LPackage pkg : lmodel.getPackages()) {
counter++;
String pkgName = qnp.getFullyQualifiedName(pkg).toString();
if (names.contains(pkgName)) {
error(String.format("Package %s must not be defined twice!",
pkgName), OSBPDtoPackage.Literals.LDTO_MODEL__PACKAGES,
counter, CODE__DUPLICATE_LPACKAGE_IN_FILE,
(String[]) null);
}
names.add(pkgName);
}
}
@Check(CheckType.NORMAL)
public void checkDuplicateTypeInProject(LType type) {
if (type instanceof LDataType) {
return;
}
super.checkDuplicateType_InProject(type);
}
@Check(CheckType.NORMAL)
public void checkDuplicateDatatypeInPackage(LTypedPackage pkg) {
super.checkDuplicateDatatypeInPackage(pkg);
}
@Check(CheckType.NORMAL)
public void checkDuplicatePackage_InProject(LPackage lPackage) {
super.checkDuplicatePackage_InProject(lPackage);
}
@Check
public void checkManyToMany(LDtoReference prop) {
DtoModelExtensions extension = new DtoModelExtensions();
if (prop.getOpposite() != null && extension.isToMany(prop)
&& extension.isToMany(prop.getOpposite())) {
error(String.format("ManyToMany relations are not permitted!", qnp
.getFullyQualifiedName(prop).toString()),
OSBPDtoPackage.Literals.LDTO_REFERENCE__OPPOSITE,
ValidationMessageAcceptor.INSIGNIFICANT_INDEX,
CODE__MANY_TO_MANY__NOT_SUPPORTED, (String[]) null);
}
}
@Check(CheckType.NORMAL)
public void checkJPA_Features(LDtoAttribute prop) {
if (prop.isUuid()) {
boolean typeOK = false;
if (prop.getType() instanceof LDataType) {
LDataType type = (LDataType) prop.getType();
String typename = type.getJvmTypeReference().getQualifiedName();
if (typename.equals("java.lang.String")) {
typeOK = true;
}
}
if (!typeOK) {
error("UUIDs must be of type String.",
OSBPTypesPackage.Literals.LATTRIBUTE__UUID,
CODE__UUID_WRONG_TYPE, new String[0]);
}
}
if (prop.isDomainKey()) {
if (extensions.isToMany(prop)) {
error("DomainKey is not valid for one to many relations.",
OSBPTypesPackage.Literals.LATTRIBUTE__DOMAIN_KEY,
CODE__DOMAIN_KEY__NO_MANY, new String[0]);
}
if (prop.getType() instanceof LDataType) {
LDataType type = (LDataType) prop.getType();
String typename = type.getJvmTypeReference().getQualifiedName();
if (!typename.equals("java.lang.String")) {
error("DomainKey must be of type String.",
OSBPTypesPackage.Literals.LATTRIBUTE__DOMAIN_KEY,
CODE__DOMAIN_KEY__TYPE, new String[0]);
}
}
}
if (prop.isDomainDescription()) {
if (extensions.isToMany(prop)) {
error("DomainDescription is not valid for one to many relations.",
OSBPTypesPackage.Literals.LATTRIBUTE__DOMAIN_DESCRIPTION,
CODE__DOMAIN_DESCRIPTION__NO_MANY, new String[0]);
}
if (prop.getType() instanceof LDataType) {
LDataType type = (LDataType) prop.getType();
String typename = type.getJvmTypeReference().getQualifiedName();
if (!typename.equals("java.lang.String")) {
error("DomainDescription must be of type String.",
OSBPTypesPackage.Literals.LATTRIBUTE__DOMAIN_DESCRIPTION,
CODE__DOMAIN_DESCRIPTION__TYPE, new String[0]);
}
}
}
if (prop.isDirty()) {
if (extensions.isToMany(prop)) {
error("Dirty is not valid for one to many relations.",
OSBPTypesPackage.Literals.LATTRIBUTE__DIRTY,
CODE__DIRT__NO_MANY, new String[0]);
}
if (prop.getType() instanceof LDataType) {
LDataType type = (LDataType) prop.getType();
String typename = type.getJvmTypeReference().getQualifiedName();
if (!typename.equals("java.lang.Boolean")
&& !typename.equals(Boolean.TYPE.getName())) {
error("Dirty is not for the datatype. Only boolean valid.",
OSBPTypesPackage.Literals.LATTRIBUTE__DIRTY,
CODE__DIRT__TYPE, new String[0]);
}
}
}
}
@Check(CheckType.NORMAL)
public void checkJPA_Features(LDto dto) {
int idCounter = 0;
int versionCounter = 0;
int domainKeyCounter = 0;
int domainDescriptionCounter = 0;
int dirtyCounter = 0;
Map<String, Integer> attNames = new HashMap<String, Integer>();
for (LFeature feature : dto.getAllFeatures()) {
if (feature instanceof LDtoAttribute) {
LDtoAttribute att = (LDtoAttribute) feature;
if (att.isId() || att.isUuid()) {
idCounter++;
}
if (att.isVersion()) {
versionCounter++;
}
if (att.isDomainKey()) {
domainKeyCounter++;
}
if (att.isDomainDescription()) {
domainDescriptionCounter++;
}
if (att.isDirty()) {
dirtyCounter++;
}
}
if (!attNames.containsKey(feature.getName())) {
attNames.put(feature.getName(), 1);
} else {
int value = attNames.get(feature.getName());
attNames.put(feature.getName(), ++value);
}
}
if (idCounter > 1) {
int i = 0;
for (LDtoFeature feature : dto.getFeatures()) {
if (feature instanceof LDtoAttribute) {
if (((LDtoAttribute) feature).isId()
|| ((LDtoAttribute) feature).isUuid()) {
error("A DTO must only have one ID property.",
OSBPDtoPackage.Literals.LDTO__FEATURES, i,
CODE__DUPLICATE_ID, new String[0]);
break;
}
}
i++;
}
}
if (versionCounter > 1) {
int i = 0;
for (LDtoFeature feature : dto.getFeatures()) {
if (feature instanceof LDtoAttribute) {
if (((LDtoAttribute) feature).isVersion()) {
error("A DTO must only have one Version property.",
OSBPDtoPackage.Literals.LDTO__FEATURES, i,
CODE__DUPLICATE_VERSION, new String[0]);
break;
}
}
i++;
}
}
if (domainKeyCounter > 1) {
int i = 0;
for (LDtoFeature feature : dto.getFeatures()) {
if (feature instanceof LDtoAttribute) {
if (((LDtoAttribute) feature).isDomainKey()) {
error("A DTO must only have one DomainKey property.",
OSBPDtoPackage.Literals.LDTO__FEATURES, i,
CODE__DUPLICATE_DOMAIN_KEY, new String[0]);
break;
}
}
i++;
}
}
if (domainDescriptionCounter > 1) {
int i = 0;
for (LDtoFeature feature : dto.getFeatures()) {
if (feature instanceof LDtoAttribute) {
if (((LDtoAttribute) feature).isDomainDescription()) {
error("A DTO must only have one DomainDescription property.",
OSBPDtoPackage.Literals.LDTO__FEATURES, i,
CODE__DUPLICATE_DOMAIN_DESCRIPTION,
new String[0]);
break;
}
}
i++;
}
}
if (dirtyCounter > 1) {
int i = 0;
for (LDtoFeature feature : dto.getFeatures()) {
if (feature instanceof LDtoAttribute) {
if (((LDtoAttribute) feature).isId()
|| ((LDtoAttribute) feature).isUuid()) {
error("A DTO must only have one dirty property.",
OSBPDtoPackage.Literals.LDTO__FEATURES, i,
CODE__DUPLICATE_DIRTY, new String[0]);
break;
}
}
i++;
}
}
for (Map.Entry<String, Integer> entry : attNames.entrySet()) {
if (entry.getValue() > 1) {
int i = 0;
for (LDtoFeature feature : dto.getFeatures()) {
if (feature.getName().equals(entry.getKey())) {
error(String.format(
"The property \"%s\" must only be defined once!",
feature.getName()),
OSBPDtoPackage.Literals.LDTO__FEATURES, i,
CODE__DUPLICATE_PROPERTY_NAME, new String[0]);
break;
}
i++;
}
}
}
}
@Check
public void checkClassPath(LTypedPackage dtoModel) {
TypeReferences typeReferences = getServices().getTypeReferences();
final JvmGenericType listType = (JvmGenericType) typeReferences
.findDeclaredType(List.class, dtoModel);
if (listType == null || listType.getTypeParameters().isEmpty()) {
error("Couldn't find a JDK 1.5 or higher on the project's classpath.",
dtoModel, OSBPTypesPackage.Literals.LPACKAGE__NAME,
CODE__MISSING__JDK_1_5);
}
if (typeReferences.findDeclaredType(
"org.eclipse.osbp.dsl.dto.lib.services.IDTOService", dtoModel) == null) {
error("Couldn't find the mandatory library 'org.eclipse.osbp.dsl.dto.lib' on the project's classpath.",
dtoModel, OSBPTypesPackage.Literals.LPACKAGE__NAME,
CODE__MISSING__DTO_LIB);
}
if (typeReferences.findDeclaredType(
"org.eclipse.osbp.runtime.common.annotations.Dispose", dtoModel) == null) {
error("Couldn't find the mandatory library 'org.eclipse.osbp.runtime.common' on the project's classpath.",
dtoModel, OSBPTypesPackage.Literals.LPACKAGE__NAME,
CODE__MISSING__L_RUNTIME_COMMON);
}
if (typeReferences.findDeclaredType(Extension.class, dtoModel) == null) {
error("Couldn't find the mandatory library 'org.eclipse.xtext.xbase.lib' 2.7.3 or higher on the project's classpath.",
dtoModel, OSBPTypesPackage.Literals.LPACKAGE__NAME,
CODE__MISSING__XBASE_LIB);
}
if (typeReferences.findDeclaredType("javax.persistence.Persistence",
dtoModel) == null) {
warning("Couldn't find the optional library 'javax.persistence' 2.1.0 or higher on the project's classpath. If you are using JPA-Dto-Services, the library is mandatory.",
dtoModel, OSBPTypesPackage.Literals.LPACKAGE__NAME,
CODE__MISSING__JAVAX_PERSISTENCE);
}
if (typeReferences.findDeclaredType(
"org.eclipse.osbp.dsl.common.datatypes.IDatatypeConstants",
dtoModel) == null) {
warning("Couldn't find the optional library 'org.eclipse.osbp.dsl.datatype.lib' on the project's classpath. This may cause resolving problems.",
dtoModel, OSBPTypesPackage.Literals.LPACKAGE__NAME,
CODE__MISSING__DATATYPE_LIB);
}
if (typeReferences.findDeclaredType("javax.validation.Valid", dtoModel) == null) {
error("Couldn't find the library 'javax.validation' on the project's classpath. This may cause resolving problems.",
dtoModel, OSBPTypesPackage.Literals.LPACKAGE__NAME,
CODE__MISSING__DATATYPE_LIB);
}
}
@Check(CheckType.FAST)
public void checkFeatureHasName(LFeature feature) {
if (feature instanceof LDtoInheritedAttribute
|| feature instanceof LDtoInheritedReference) {
return;
}
super.checkFeatureHasName(feature);
}
}