blob: 0f5a23ccee5b5ad2cabdd0748f89a5fb35bf307a [file] [log] [blame]
/*
*
* Copyright (c) 2013, 2016 - 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:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*
*/
package org.eclipse.osbp.xtext.datamartdsl.validation
import com.google.inject.Inject
import java.util.List
import java.util.Set
import org.eclipse.osbp.xtext.basic.validation.IBasicValidatorDelegate
import org.eclipse.osbp.xtext.datamartdsl.AxisEnum
import org.eclipse.osbp.xtext.datamartdsl.ConditionalExpression
import org.eclipse.osbp.xtext.datamartdsl.Conjunction
import org.eclipse.osbp.xtext.datamartdsl.DatamartAttribute
import org.eclipse.osbp.xtext.datamartdsl.DatamartAttributeBase
import org.eclipse.osbp.xtext.datamartdsl.DatamartCube
import org.eclipse.osbp.xtext.datamartdsl.DatamartCubeAxis
import org.eclipse.osbp.xtext.datamartdsl.DatamartDSLPackage
import org.eclipse.osbp.xtext.datamartdsl.DatamartDefinition
import org.eclipse.osbp.xtext.datamartdsl.DatamartEntity
import org.eclipse.osbp.xtext.datamartdsl.DatamartHierarchy
import org.eclipse.osbp.xtext.datamartdsl.DatamartHierarchyLevel
import org.eclipse.osbp.xtext.datamartdsl.DatamartHierarchyLevelMultiple
import org.eclipse.osbp.xtext.datamartdsl.DatamartHierarchyLevelSingle
import org.eclipse.osbp.xtext.datamartdsl.DatamartSetFunction
import org.eclipse.osbp.xtext.datamartdsl.DatamartSetTuple
import org.eclipse.osbp.xtext.datamartdsl.DatamartTask
import org.eclipse.osbp.xtext.datamartdsl.Expression
import org.eclipse.osbp.xtext.datamartdsl.SetFunctionEnum
import org.eclipse.osbp.xtext.datamartdsl.util.DatamartAttributeUtil
import org.eclipse.osbp.xtext.datamartdsl.util.DatamartHierarchyUtil
import org.eclipse.xtext.validation.Check
/**
* Custom validation rules.
*
* see http://www.eclipse.org/Xtext/documentation.html#validation
*/
class DatamartDSLValidator extends AbstractDatamartDSLValidator {
@Inject(optional=true) IBasicValidatorDelegate delegate
@Inject extension DatamartHierarchyUtil
@Check
def checkCommercialLicensed(DatamartDefinition datamart) {
if ((datamart.source instanceof DatamartTask)) {
if(delegate !== null && !delegate.validateCommercial("datamart", "net.osbee.bpm")) {
info('''BPM is needed and not yet licensed. License BPM at www.osbee.net''', datamart, null)
}
}
if ((datamart.source instanceof DatamartCube)) {
if(delegate !== null && !delegate.validateCommercial("datamart", "net.osbee.xtext.cube")) {
info('''Cube is needed and not yet licensed. License Cube at www.osbee.net''', datamart, null)
}
}
}
@Check
def checkForDuplicatedAttributeNamesOrAliases(DatamartAttribute attribute) {
var attributeNames = <String>newHashSet()
var eObj = attribute.eContainer
while ((eObj !== null) && !(eObj instanceof DatamartEntity)){
eObj = eObj.eContainer
}
if (eObj !== null){
(eObj as DatamartEntity).checkForDuplicatedAttributeNamesOrAliases(attributeNames)
}
}
private def void checkForDuplicatedAttributeNamesOrAliases(DatamartEntity entity, Set<String> attributeNames) {
var error = false
for (attribute : entity.attributes) {
var added = attributeNames.add(DatamartAttributeUtil.getAliasedAttributeName(attribute))
if (!added){
error = true
var errorTxt = '''Duplicated attribute names or aliases are not allowed in the same datamart definition.'''
if (attribute.aliased){
error(errorTxt, attribute, DatamartDSLPackage.Literals.DATAMART_ATTRIBUTE__ALIAS_NAME)
} else {
error(errorTxt, attribute, DatamartDSLPackage.Literals.DATAMART_ATTRIBUTE_BASE__ATTRIBUTE_REF)
}
}
}
if (!error){
var eObj = entity.eContainer
while ((eObj !== null) && !(eObj instanceof DatamartEntity)){
eObj = eObj.eContainer
}
if (eObj !== null){
(eObj as DatamartEntity).checkForDuplicatedAttributeNamesOrAliases(attributeNames)
}
}
}
/**
* Checks if both axis "rows" and "columns" are defined when a DatamartCube definition contains either the axis "pages", "chapters" "sections" or all 3 of them.
*/
@Check
def checkForRowsAndColumnsPresenceInCube(DatamartCube cube) {
var error = false
var hasAxisColumns = cube.axisslicer.exists[it instanceof DatamartCubeAxis && (it as DatamartCubeAxis).axis.name == AxisEnum.COLUMNS]
var hasAxisRows = cube.axisslicer.exists[it instanceof DatamartCubeAxis && (it as DatamartCubeAxis).axis.name == AxisEnum.ROWS]
var axisPages = cube.axisslicer.findFirst[it instanceof DatamartCubeAxis && (it as DatamartCubeAxis).axis.name == AxisEnum.PAGES]
var axisChapters = cube.axisslicer.findFirst[it instanceof DatamartCubeAxis && (it as DatamartCubeAxis).axis.name == AxisEnum.CHAPTERS]
var axisSections = cube.axisslicer.findFirst[it instanceof DatamartCubeAxis && (it as DatamartCubeAxis).axis.name == AxisEnum.SECTIONS]
//Pages
if(axisPages!==null && !hasAxisColumns || axisPages!==null && !hasAxisRows){
error = true
var errorTxt = ''' "pages" can't be used without setting up both "columns" and "rows".'''
error(errorTxt, axisPages, DatamartDSLPackage.Literals.DATAMART_CUBE_AXIS__AXIS)
}
//Chapters
if(axisChapters!==null && !hasAxisColumns || axisChapters!==null && !hasAxisRows){
error = true
var errorTxt = ''' ''chapters'' can't be used without setting up both ''columns'' and ''rows''.'''
error(errorTxt, axisChapters, DatamartDSLPackage.Literals.DATAMART_CUBE_AXIS__AXIS)
}
//Sections
if(axisSections!==null && !hasAxisColumns || axisSections!==null && !hasAxisRows){
error = true
var errorTxt = ''' ''sections'' can't be used without setting up both ''columns'' and ''rows''.'''
error(errorTxt, axisSections, DatamartDSLPackage.Literals.DATAMART_CUBE_AXIS__AXIS)
}
}
/**
* Checks if both axis "rows" and "columns" are defined when a DatamartEntity definition contains either the axis "pages", "chapters" "sections" or all 3 of them.
*/
@Check
def checkForRowsAndColumnsPresenceInEntity(DatamartEntity entity) {
var error = false
var hasAxisColumns = entity.attributes.exists[it instanceof DatamartAttribute && (it as DatamartAttribute).axis.name == AxisEnum.COLUMNS]
var hasAxisRows = entity.attributes.exists[it instanceof DatamartAttribute && (it as DatamartAttribute).axis.name == AxisEnum.ROWS]
var axisPages = entity.attributes.findFirst[it instanceof DatamartAttribute && (it as DatamartAttribute).axis.name == AxisEnum.PAGES]
var axisChapters = entity.attributes.findFirst[it instanceof DatamartAttribute && (it as DatamartAttribute).axis.name == AxisEnum.CHAPTERS]
var axisSections = entity.attributes.findFirst[it instanceof DatamartAttribute && (it as DatamartAttribute).axis.name == AxisEnum.SECTIONS]
//Pages
if(axisPages!==null && !hasAxisColumns || axisPages!==null && !hasAxisRows){
error = true
var errorTxt = ''' ''pages'' can't be used without setting up both ''columns'' and ''rows''.'''
error(errorTxt, axisPages, DatamartDSLPackage.Literals.DATAMART_ATTRIBUTE__AXIS)
}
//Chapters
if(axisChapters!==null && !hasAxisColumns || axisChapters!==null && !hasAxisRows){
error = true
var errorTxt = ''' ''chapters'' can't be used without setting up both ''columns'' and ''rows''.'''
error(errorTxt, axisChapters, DatamartDSLPackage.Literals.DATAMART_ATTRIBUTE__AXIS)
}
//Sections
if(axisSections!==null && !hasAxisColumns || axisSections!==null && !hasAxisRows){
error = true
var errorTxt = ''' ''sections'' can't be used without setting up both ''columns'' and ''rows''.'''
error(errorTxt, axisSections, DatamartDSLPackage.Literals.DATAMART_ATTRIBUTE__AXIS)
}
}
/**
* Checks that no transient attribute is used.
*/
@Check
def checkForTransientAttribute(DatamartAttributeBase attribute) {
val entityAttribute = attribute.attributeRef
var error = false
if ((entityAttribute.eIsProxy) || (!entityAttribute.eIsProxy && entityAttribute.transient)) {
error = true
var errorTxt = ''' ''attribute'' can't refer to an unresolved or transient entity attribute.'''
error(errorTxt, attribute, DatamartDSLPackage.Literals.DATAMART_ATTRIBUTE_BASE__ATTRIBUTE_REF)
}
}
/**
* Checks that two same hierarchies are not used in the same datamart axis row definition.
*/
// @Check
// def checkForUniqueHierarchy(DatamartHierarchy hierarchy) {
// var error = false
// var parent = hierarchy.eContainer
// if (parent instanceof DatamartCubeAxis) {
// var hierarchiesFound = 0
// for (element : (parent as DatamartCubeAxis).elements) {
// if (element instanceof DatamartHierarchy) {
// if (hierarchy.hierarchyRef.name.equals((element as DatamartHierarchy).hierarchyRef.name)) {
// hierarchiesFound++
// }
// }
// if (hierarchiesFound > 1) {
// error = true
// var errorTxt = ''' ''hierarchy'' can't refer to more than one member of the same hierarchy.'''
// error(errorTxt, hierarchy, DatamartDSLPackage.Literals.DATAMART_HIERARCHY__HIERARCHY_REF)
// }
// }
// }
// }
@Check
def checkNoLevelInYtd(DatamartHierarchy hierarchy){
var eObject = hierarchy.eContainer
while ((eObject!==null) && !(eObject instanceof DatamartSetTuple)){
eObject = eObject.eContainer
}
if (eObject !== null){
var function = (eObject as DatamartSetTuple).left.setFunction
if ((function instanceof DatamartSetFunction) && SetFunctionEnum.YTD.equals((function as DatamartSetFunction).setFunction)){
if (hierarchy.existLevelDefinition){
var errorTxt = ''' ''hierarchy'' can't define a level as part of the '«SetFunctionEnum.YTD.literal»' function. Please remove the complete level.'''
error(errorTxt, hierarchy, DatamartDSLPackage.Literals.DATAMART_HIERARCHY__LEVEL)
}
}
}
}
@Check
def checkSortedInLevel(DatamartHierarchyLevel hierarchyLevel){
if (hierarchyLevel instanceof DatamartHierarchyLevelMultiple) {
var sorted = 0
for (level : hierarchyLevel.levels) {
if (level.sorted) sorted++
if (sorted > 1) {
var errorTxt = ''' Only one level is allowed to have the ''sorted'' attribute. Please remain only one ''sorted'' attribute.'''
error(errorTxt, hierarchyLevel, DatamartDSLPackage.Literals.DATAMART_HIERARCHY_LEVEL_SINGLE__SORTED)
}
}
} else {
if (!(hierarchyLevel.eContainer instanceof DatamartHierarchyLevelMultiple)) {
if ((hierarchyLevel instanceof DatamartHierarchyLevelSingle) && (hierarchyLevel as DatamartHierarchyLevelSingle).sorted) {
var errorTxt = ''' Only a level of a hierarchized hierarchy is allowed to have the ''sorted'' attribute. Please remove it.'''
error(errorTxt, hierarchyLevel, DatamartDSLPackage.Literals.DATAMART_HIERARCHY_LEVEL_SINGLE__SORTED)
}
}
}
}
@Check
def checkConditions(DatamartEntity entity){
for(datamartCondition : entity.conditions) {
var rangedList = <String>newArrayList()
var filteredList = <String>newArrayList()
fillRangedAndFilteredExpression(datamartCondition.condition, rangedList, filteredList)
for (filteredAttribute : filteredList){
if (rangedList.contains(filteredAttribute)){
var errorTxt = '''A filtered and a ranged condition is not allowed on the same attribute.'''
error(errorTxt, datamartCondition, DatamartDSLPackage.Literals.DATAMART_CONDITION__CONDITION)
}
}
}
}
def void fillRangedAndFilteredExpression(Expression expression, List<String> rangedList, List<String> filteredList){
if (expression instanceof ConditionalExpression) {
var conditionalExpression = expression as ConditionalExpression
if (conditionalExpression.right.ranged){
if (conditionalExpression.left instanceof DatamartAttributeBase){
var attributeName = (conditionalExpression.left as DatamartAttributeBase).attributeRef.name
if (attributeName!==null){
rangedList.add(attributeName)
}
}
} else if (conditionalExpression.right.filtered){
if (conditionalExpression.left instanceof DatamartAttributeBase){
var attributeName = (conditionalExpression.left as DatamartAttributeBase).attributeRef.name
if (attributeName!==null){
filteredList.add(attributeName)
}
}
}
} else if (expression instanceof Conjunction) {
fillRangedAndFilteredExpression(expression.left, rangedList, filteredList);
fillRangedAndFilteredExpression(expression.right, rangedList, filteredList);
}
}
}