| /** |
| * 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 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * 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.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 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 com.google.inject.Inject; |
| |
| /** |
| * Custom validation rules. |
| * |
| * see http://www.eclipse.org/Xtext/documentation.html#validation |
| */ |
| @SuppressWarnings("restriction") |
| public class DtoGrammarValidator extends org.eclipse.osbp.dsl.dto.xtext.validation.AbstractDtoGrammarValidator { |
| |
| 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"; |
| private static final String CODE__DTO_NAME = "122"; |
| |
| @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.isCascadeMergePersist() || prop.isCascadeRemove()) { |
| 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_NotAlsoCascadeMergePersist(LDtoReference prop) { |
| if (prop.getOpposite() != null) { |
| if (prop.isCascadeMergePersist() && prop.getOpposite().isCascadeMergePersist()) { |
| error("Only one opposite may be specified as cascade", OSBPTypesPackage.Literals.LREFERENCE__CASCADE_MERGE_PERSIST, |
| CODE__BIDIRECTIONAL_CASCADE_INVALID, (String[]) null); |
| } |
| |
| if (extensions.isToMany(prop.getOpposite())) { |
| if (prop.isCascadeMergePersist()) { |
| error("Cascade must not affect the common parent in a many-to-one relation", prop, |
| OSBPTypesPackage.Literals.LREFERENCE__CASCADE_MERGE_PERSIST, CODE__CASCADE_DIRECTION_INVALID, |
| new String[0]); |
| } |
| } |
| } |
| } |
| |
| @Check |
| public void checkOpposite_NotAlsoCascadeRemove(LDtoReference prop) { |
| if (prop.getOpposite() != null) { |
| if (prop.isCascadeRemove() && prop.getOpposite().isCascadeRemove()) { |
| error("Only one opposite may be specified as cascade", OSBPTypesPackage.Literals.LREFERENCE__CASCADE_REMOVE, |
| CODE__BIDIRECTIONAL_CASCADE_INVALID, (String[]) null); |
| } |
| |
| if (extensions.isToMany(prop.getOpposite())) { |
| if (prop.isCascadeRemove()) { |
| error("Cascade must not affect the common parent in a many-to-one relation", prop, |
| OSBPTypesPackage.Literals.LREFERENCE__CASCADE_REMOVE, 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_OneIsCascadeMergePersist(LDtoReference prop) { |
| if (prop.getOpposite() != null) { |
| if (!prop.isCascadeMergePersist() && !prop.getOpposite().isCascadeMergePersist()) { |
| error("Opposite references may only defined for cascading relations.", prop, |
| OSBPTypesPackage.Literals.LREFERENCE__CASCADE_MERGE_PERSIST, CODE__OPPOSITE_WITHOUT_CASCADE, new String[0]); |
| } |
| } |
| } |
| |
| @Check |
| public void checkOpposite_OneIsCascadeRemove(LDtoReference prop) { |
| if (prop.getOpposite() != null) { |
| if (!prop.isCascadeRemove() && !prop.getOpposite().isCascadeRemove()) { |
| error("Opposite references may only defined for cascading relations.", prop, |
| OSBPTypesPackage.Literals.LREFERENCE__CASCADE_MERGE_PERSIST, 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 checkDtoName(LDto dto) { |
| if (dto.getName() != null && !dto.getName().endsWith("Dto")) { |
| error("A Dto's name must end with 'Dto'", OSBPTypesPackage.Literals.LTYPE__NAME, |
| ValidationMessageAcceptor.INSIGNIFICANT_INDEX, CODE__DTO_NAME, 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() != null && 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.impl.DtoServiceAccess", 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.11.0 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); |
| } |
| } |