<#--
   ******************************************************
   *
   *                       NOTICE
   *
   *  THIS SOFTWARE IS THE PROPERTY OF AND CONTAINS
   *  CONFIDENTIAL INFORMATION OF INFOR, AND SHALL NOT BE
   *  COPIED, USED, NOR DISCLOSED WITHOUT EXPRESS WRITTEN
   *  AUTHORIZATION.  ALTHOUGH PUBLICATION IS NOT
   *  INTENDED, IN THE EVENT OF PUBLICATION, THE
   *  FOLLOWING NOTICE IS APPLICABLE:
   *
   *  Copyright © 2009 Infor. All rights reserved.
   *  The word and design marks set forth herein are
   *  trademarks and/or registered trademarks of Infor
   *  and/or related affiliates and subsidiaries.
   *  All rights reserved. All other trademarks listed
   *  herein are the property of their respective owners.
   *  www.infor.com.
   *
   ******************************************************
  -->
<#compress>
<#--=========================== DOCUMENTATION ===========================-->
<#-- The constraint checks implemented here are listed in function constraintDescription().
Notes:
- Constraint checks will only result in warnings.
  However, violation of these checks may result in compilation errors.
- Constraint checks should be implemented here if they are specific for ERP LN.
  Other (generic) constraints must result in a 'problem' in the Integration Studio.
-->
<#-- This file is not yet complete. Some checks are not implemented yet.
     Other checks are implemented but should be moved to the Integration Studio, because they are not for ERP LN only.
-->
<#--=========================== FUNCTION constraintDescription ===========================-->
<#function constraintDescription iConstraint iArg1="" iArg2="" iArg3="" iArg4="" iArg5="">
	<#-- Note: constraint description naming includes the number of used arguments between brackets-->
	<#-- METHOD CONSTRAINTS -->
	<#-- Method Constraints - Dependencies -->
	<#switch iConstraint>
		<#case "a0(1)">
			<#return "No method implementation found.">
		<#break>
		<#case "a1(2)">
			<#return "If method "+iArg1+" exists then method "+iArg2+" must also exist.">
		<#break>
		<#case "a1(3)">
			<#return "Method "+iArg2+" may not be in an alternative implementation while method "+iArg1+" exists in normal implementation.">
		<#break>
		<#case "a2(2)">
			<#return "If method "+iArg1+" exists then method "+iArg2+" must also exist, because the BII has more than one component.">
		<#break>
		<#case "a3(2)">
			<#return "Method  "+iArg1+" from component "+iArg2+" must also be implemented on its parent component(s).">
		<#break>
		<#case "a4(1)">
			<#return "Method  "+iArg1+" must never be implemented in a business interface implementation for ERP LN.">
		<#break>"
		<#case "a5(1)">
			<#return "Method "+iArg1+" does not have alternative implementation, so "+iArg2+" must also not have it.">
		<#break>
		<#case "a6(1)">
			<#return "Method "+iArg1+" must never be implemented in a business interface implementation for BaanIV.">
		<#break>"
		<#case "a7(1)">
			<#return "No referential integrity tables (like "+iArg1+") are allowed for BaanIV.">
		<#break>"
		<#--#TODO some methods must exist for all components? E.g. Delete method if Change method exists?-->
	<#-- Method Constraints - Method Argument Scope -->
		<#case "b1(4)">
			<#if iArg2=="">
				<#return "Scope '"+iArg1+"' is not allowed for argument of method "+iArg3+" (component "+iArg4+").">
			<#else>
				<#return "Scope '"+iArg1+"' is not allowed for argument '"+iArg2+"' of method "+iArg3+" (component "+iArg4+").">
			</#if>
		<#break>
		<#case "b2(4)">
		<#case "b1(4)">
			<#if iArg2=="">
				<#return "Scope '"+iArg1+"' is not allowed for non-identifying argument of method "+iArg3+" (component "+iArg4+").">
			<#else>
				<#return "Scope '"+iArg1+"' is not allowed for non-identifying argument '"+iArg2+"' of method "+iArg3+" (component "+iArg4+").">
			</#if>
		<#break>
	<#-- Method Constraints - Controlling Attributes -->
		<#case "c1(3)">
			<#return "Method "+iArg1+": a method argument ("+iArg2+"."+iArg3+") cannot be a controlling attribute.">
		<#break>
		<#case "c2(3)">
			<#return "Method "+iArg1+": a method argument ("+iArg2+"."+iArg3+") cannot be a qualifier.">
		<#break>
	<#-- Method Constraints - Processing Order -->
		<#case "d1(3)">
			<#return "Processing order of standard method "+iArg1+" (component "+iArg2+") must not be '"+iArg3+"'.">
		<#break>
		<#case "d2(3)">
			<#return "Processing order of standard method "+iArg1+" (component "+iArg2+") must not be '"+iArg3+"'; use 'batch' instead.">
		<#break>
		<#case "d3(2)">
			<#return "Processing order of standard method "+iArg1+" (component "+iArg2+") can only be 'batch' if an on execute hook exists.">
		<#break>
		<#case "d4(2)">
			<#return "Processing order of List and Show must be the same (method "+iArg1+" for component "+iArg2+" is 'batch', but the other method isn't).">
		<#break>
	<#-- Method Constraints - Implementations on Subcomponents -->
		<#case "e1(2)">
			<#return "Implementation for method "+iArg1+" is ignored for child component "+iArg2+".">
		<#break>
		<#case "e2(2)">
			<#return "Implementation for batch method "+iArg1+" must not exist for a subcomponent ("+iArg2+").">
		<#break>
		<#case "e3(2)">
			<#return "onExecuteHook is ignored for method "+iArg1+" (component "+iArg2+").">
		<#break>
	<#-- Method Constraints - modules, procedures etc. -->
		<#-- #TODO to be added -->
	<#-- Method Constraints - Required Table Mappings -->
		<#case "f1(0)">
			<#return "If BII has no table mappings then List and Show method must not be implemented.">
		<#break>
	<#-- Method Constraints - Required Protected method arguments -->
		<#case "r1(3)">
			<#return "Protected method argument is missing for identifying attribute '"+iArg1+"' for the "+iArg2+" method in component '"+iArg3+"'.">
		<#break>
		<#case "r1(4)">
			<#return "Protected method argument '"+iArg1+"' for the "+iArg2+" method in component '"+iArg3+"' may not be mandatoy.">
		<#break>
	<#-- ACTION TYPE CONSTRAINTS -->
	<#-- actionType constraints -->
		<#case "g1(2)">
			<#return "Action Type contraint violation; Standard method "+iArg1+" other than Change, PublishEvent or OnEvent of component "+iArg2+" has an actionType component qualifier specified.">
		<#break>
		<#case "g2(3)">
			<#return "Action Type contraint violation; The "+iArg1+" method of component "+iArg2+" has an actionType component qualifier specified that allows an other value ('"+iArg3+"') than 'create', 'change', 'delete', 'unchanged' or 'createOrChange'.">
		<#break>
		<#case "g3(3)">
			<#return "Action Type contraint violation; The "+iArg1+" method of component "+iArg2+" has an actionType component qualifier specified with a datatype '"+iArg3+"' which has no enumeration defined. This allows any other value than 'create', 'change', 'delete', 'unchanged' or 'createOrChange'.">
		<#break>
	<#-- COMPONENT/ATTRIBUTE/TABLE CONSTRAINTS -->
	<#-- Component/Attribute/Table Constraints - Aggregations -->
		<#case "k1(1)">
			<#return "For child component "+iArg1+", an aggregation relation must be defined.">
		<#break>
		<#case "k2(3)">
			<#return "RelationshipImplementationAttribute "+iArg1+" in aggregation must relate key column of "+iArg2+" table to key column of "+iArg3+" table.">
		<#break>
		<#case "k3(3)">
			<#return "Aggregation relation for component "+iArg1+" must have a RelationshipImplementationAttribute for identifying attribute "+iArg2+"  of parent component "+iArg3+".">
		<#break>
		<#case "k4(2)">
			<#return "Associated attribute '"+iArg1+"' refers towards Business Interface Implementation '"+iArg2+"' for which no Implementation Identifier is defined.">
		<#break>
		<#case "k5(3)">
			<#return "RelationshipImplementationAttribute "+iArg1+" in aggregation from "+iArg2+" to "+iArg3+" misses a reference.">
		<#break>
	<#-- Component/Attribute/Table Constraints - Identifiers -->
		<#case "m1(3)">
			<#return "Column "+iArg1+"."+iArg2+" of root table must be mapped to an identifying attribute implementation of component "+iArg3+".">
		<#break>
		<#case "m2(0)">
			<#return "If BII has method List or Show or SubscribeEvent, in case of more than one component and components are mapped to tables, components must be linked as follows: all identifying attributes of parent component that are linked directly to a key column must be linked to identifying attributes of table component that are linked directly to a key column. Calculated attributes must not be used to defined the relation.">
		<#break>
	<#-- Component/Attribute/Table Constraints - Data Types -->
		<#case "n1(3)">
			<#return "Datatype "+iArg1+" of attribute implementation "+iArg2+"."+iArg3+" must have a native data type specified.">
		<#break>
		<#case "n2(2)">
			<#return "Attribute implementation "+iArg1+"."+iArg2+" should not have a data type specified, because it is mapped directly to a table column.">
		<#break>
		<#case "n3(2)">
			<#return "The native data type used by attribute implementation "+iArg1+"."+iArg2+" is not a valid ERP LN domain.">
		<#break>
		<#case "n4(3)">
			<#return "Datatype dimensions value ("+iArg1+") of attribute implementation "+iArg2+"."+iArg3+" is not valid.">
		<#break>
		<#case "n5(4)">
			<#return "Number of elements ("+iArg1+") differs from dimensions value ("+iArg2+") of attribute implementation "+iArg3+"."+iArg4+".">
		<#break>
		<#case "n6(2)">
			<#return "Attribute implementation "+iArg1+"."+iArg2+" must have a data type, either directly or through its column, associated attribute or interaction point.">
		<#break>
	<#-- Component/Attribute/Table Constraints - Non-Root Tables -->
		<#case "o1(1)">
			<#return "Cycles or self-references found in tabels of component "+iArg1>
		<#break>
		<#case "o2(1)">
			<#return "Not all tables of component "+iArg1+" are related with each other">
		<#break>
		<#case "o3(3)">
			<#return "For identifier '"+iArg1+"' of non-root table '"+iArg2+"' no attribute implementation on component '"+iArg3+"' exists">
		<#break>
	<#-- Component/Attribute/Table Constraints - Attribute Grouping -->
		<#case "p1(0)">
			<#return "If one attribute from a group is mandatory then the group must also be mandatory.">
		<#break>
		<#case "p2(0)">
			<#return "If an attribute group is mandatory it must contain at least one mandatory attribute.">
		<#break>
		<#case "p3(0)">
			<#return "If an attribute group is read-only then all its children must be read-only.">
		<#break>
	<#-- Component/Attribute/Table Constraints - Components -->
		<#case "q1(1)">
			<#return "Duplicate component names are not allowed; component '"+iArg1+"'">
		<#break>
	<#-- Conversion Hook on Protected Attributes -->
		<#case "s1(3)">
			<#return "Conversion "+iArg1+" Hook will not be used for Protected Attribute '"+iArg2+"."+iArg3+"'">
		<#break>
	<#-- GENERAL CHECKS -->
		<#case "x1(0)">
			<#return "Using tables of type 'form' is unsupported in ERP LN.">
		<#break>
		<#case "x2(1)">
			<#return "Business interface name "+iArg1+" cannot be used for ERP LN because length is greater than 40.">
		<#break>
		<#case "x3(2)">
			<#return "BII name '"+iArg1+"' must be equal to BID name '"+iArg2+"' + 'BOD'.">
		<#break>
		<#case "x4(1)">
			<#return "Event '"+iArg1+"' modeled for BDE BID (for BDEs no events should be modeled).">
		<#break>
		<#case "x5(1)">
			<#return "Event '"+iArg1+"' modeled, but this is not a BOD verb that can be sent or received.">
		<#break>
		<#case "x6(1)">
			<#return "Event '"+iArg1+"' modeled (this event is not supported yet).">
		<#break>
		<#case "x7(1)">
			<#return "Event '"+iArg1+"' is modeled as an event to be received, but this event cannot be received by ERP LN.">
		<#break>
	<#-- DEFAULT -->
		<#default>
			<#return "An unknown constraint '"+iConstraint+"' was violated.">
		<#break>
	</#switch> <#--iConstraint-->
</#function> <#--constraintDescription-->
<#--=========================== MACRO ConstraintViolation ===========================-->
<#macro ConstraintViolation iConstraint iDetails="" iWarning=true>
	<#local constraintDescription="ERP LN constraint: "+iConstraint/>
	<#if iDetails!="">
		<#local constraintDescription=constraintDescription+" ["+iDetails+"]"/>
	</#if> <#--iDetails!=""-->
	<#if iWarning>
		${logger.warn(object, constraintDescription)}
	<#else> <#--iWarning-->
		${logger.error(object, constraintDescription)}
	</#if> <#--iWarning-->
	<@writeCommentLine iComment="Constraint violation:	"+constraintDescription/>
	<#-- comment is added to source so we can see the problem in the ERP LN library as well -->
</#macro> <#--ConstraintViolation-->
<#--=========================== FUNCTION writeCommentLine ===========================-->
<#macro writeCommentLine iComment="">
	<#if (iComment?length>120)>
| ${iComment[0..120]}
	<#else>
| ${iComment}
	</#if>
</#macro> <#--writeCommentLine-->
<#--=========================== FUNCTION hasMoreThanOneComponent ===========================-->
<#--moved (for reuse) to bdeHasMoreThanOneComponent in common.defs.ftl-->
<#--=========================== FUNCTION listTables2 ===========================-->
<#--#TODO update listTables in protected.st.common.ftl (add line containing componentImplementation) and use that function-->
<#function listTables2>
	<#local container=[]>
	<#list protected.listProtectedComponents() as c>
		<#list c.componentImplementation.componentImplementationTable as ct>
			<#local table={
				"tableName":ct.table.idref.name,
				"table":ct.table.idref,
				"isRootTable":ct.isRootTable,
				"isReferentialIntegrityTable":ct.isReferentialIntegrityTable,
				"componentImplementation":c.componentImplementation
			}>
			<#if !container?seq_contains(table)>
				<#local container=container+[table]>
			</#if>
		</#list>
	</#list>
	<#return container>	
</#function>
<#--=========================== FUNCTION checkTableStructureOfComponent ===========================-->
<#function determineReachedTables iTable iComponent iReachedTables iBothDirections>
	<#local reachedTables=iReachedTables>
	<#local count=0>
	<#list iComponent.componentImplementation.componentImplementationTable as cit>
		<#-- From iTable -->
		<#if cit.name == iTable>
			<#list cit.componentImplementationTableDetail as citd>
				<#local toTable=citd.toComponentImplementationTable.value>
				<#if !protected.containedIn(toTable, reachedTables)>
					<#local reachedTables=reachedTables+[toTable]>
					<#local count=count+1>
					<#local reachedByTo=determineReachedTables(toTable, iComponent, reachedTables, iBothDirections)>
					<#local count=count+reachedByTo.count>
					<#local reachedTables=reachedByTo.reachedTables>
				</#if>
			</#list>
		</#if>
		<#if iBothDirections>
			<#-- To iTable -->
			<#list cit.componentImplementationTableDetail as citd>
				<#local toTable=citd.toComponentImplementationTable.value>
				<#if toTable == iTable>
					<#local fromTable=cit.name>
					<#if !protected.containedIn(fromTable, reachedTables)>
						<#local reachedTables=reachedTables+[fromTable]>
						<#local count=count+1>
						<#local reachedByTo=determineReachedTables(fromTable, iComponent, reachedTables, iBothDirections)>
						<#local count=count+reachedByTo.count>
						<#local reachedTables=reachedByTo.reachedTables>
					</#if>
				</#if>
			</#list>
		</#if>
	</#list>
	<#return {"count":count, "reachedTables":reachedTables}>
</#function>

<#function checkTableStructureOfComponent iComponent>
	<#local isCycleFree=true>
	<#local isCoherent=false>
	<#local nrOfTables=0>
	<#list iComponent.componentImplementation.componentImplementationTable as cit>
		<#local nrOfTables=nrOfTables+1>
	</#list>
	<#if nrOfTables==0>
		<#local isCoherent=true>
	</#if>
	<#list iComponent.componentImplementation.componentImplementationTable as cit>
		<#-- check cycle-freeness: true unless a table can reach itself following the
			relations in single direction -->
		<#if isCycleFree>
			<#local drt=determineReachedTables(cit.table.idref.name, iComponent, [], false)>
			<#if protected.containedIn(cit.table.idref.name, drt.reachedTables)>
				<#local isCycleFree=false>
			</#if>
		</#if>
		<#-- check coherence: false unless a table can reach all other tables following the
			relations in both directions -->
		<#if !isCoherent>
			<#local drt=determineReachedTables(cit.name, iComponent, [cit.name], true)>
			<#if drt.count == nrOfTables-1>
				<#local isCoherent=true>
			</#if>
		</#if>
	</#list>

	<#return {"cycleFree":isCycleFree, "coherent":isCoherent}>
</#function>
<#--=========================== FUNCTION columnLinkedToAttributeImplementation ===========================-->
<#function isColumnLinkedToAttributeImplementation iTableName iColumnName iComponent iSearchFromTable=true iSearchToTable=true>
	<#-- checks if a table column is linked to an attribute implementation on the component,
		either directly or via links to other tables -->
	<#-- check direct links -->
	<#list iComponent.componentImplementation.attributeImplementation as ai>
		<#if ai.componentImplementationTable?exists>
			<#if ai.componentImplementationTable.idref.table.idref.name == iTableName && ai.column.idref.name == iColumnName>
				<#return true>
			</#if>
		</#if>
	</#list>
	<#-- no direct link: follow links to other tables -->
	<#list iComponent.componentImplementation.componentImplementationTable as cit>
		<#if iSearchFromTable>
			<#-- Relations from iTableName -->
			<#if cit.table.idref.name == iTableName>
				<#list cit.componentImplementationTableDetail as citd>
					<#if citd.column.idref.name == iColumnName>
						<#local toTable=citd.toComponentImplementationTable.idref.table.idref.name>
						<#local toColumn=citd.toColumn.idref.name>
						<#return isColumnLinkedToAttributeImplementation(toTable, toColumn, iComponent, true, false)>
					</#if>
				</#list>
			</#if>
		</#if>
		<#if iSearchToTable>
			<#-- Relations to iTableName -->
			<#list cit.componentImplementationTableDetail as citd>
				<#local toTable=citd.toComponentImplementationTable.idref.table.idref.name>
				<#if toTable == iTableName && citd.toColumn.idref.name == iColumnName>
					<#local fromTable=cit.table.idref.name>
					<#local fromColumn=citd.column.idref.name>
					<#return isColumnLinkedToAttributeImplementation(fromTable, fromColumn, iComponent, false, true)>
				</#if>
			</#list>
		</#if>
	</#list>
	<#-- no link to other tables, hence no link at all -->
	<#return false>
</#function>
<#--=========================== METHOD CONSTRAINTS: Dependencies ===========================-->
<#assign methodFound=false>
<#list object.methodImplementation as methodImplementation>
	<#assign methodFound=true>
	<#break>
</#list>
<#if !methodFound>
	<@ConstraintViolation iConstraint=constraintDescription("a0(1)") iWarning=true/>
</#if>
<#if common.methodPresent("Read")>
	<@ConstraintViolation iConstraint=constraintDescription("a4(1)", "Read")/>
</#if>
<#if object.businessInterfaceDefinition.idref.type != "bod">
	<#if common.methodPresent("SubscribeEvent")>
		<#if names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0">
			<@ConstraintViolation iConstraint=constraintDescription("a6(1)", "SubscribeEvent") iWarning=false/>
		<#else>
			<#if !common.methodPresent("Show")>
				<@ConstraintViolation iConstraint=constraintDescription("a1(2)", "SubscribeEvent", "Show")/>
			</#if> <#--!common.methodPresent("Show")-->
			<#if !common.methodPresent("PublishEvent")>
				<@ConstraintViolation iConstraint=constraintDescription("a1(2)", "SubscribeEvent", "PublishEvent")/>
			</#if> <#--!common.methodPresent("PublishEvent")-->
		</#if><#--names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0"-->
	</#if> <#--common.methodPresent("SubscribeEvent")-->
	<#if common.methodPresent("SubscribeList")>
		<#if names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0">
			<@ConstraintViolation iConstraint=constraintDescription("a6(1)", "SubscribeList") iWarning=false/>
		<#else>
			<#if !common.methodPresent("PublishEvent")>
				<@ConstraintViolation iConstraint=constraintDescription("a1(2)", "SubscribeList", "PublishEvent")/>
			</#if> <#--!common.methodPresent("PublishEvent")-->
			<#if !common.methodPresent("List")>
				<@ConstraintViolation iConstraint=constraintDescription("a1(2)", "SubscribeList", "List")/>
			</#if> <#--!common.methodPresent("List")-->
		</#if><#--names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0"-->
	</#if> <#--common.methodPresent("SubscribeList")-->
	<#if names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0">
		<#if common.methodPresent("Subscribe")>
			<@ConstraintViolation iConstraint=constraintDescription("a6(1)", "Subscribe") iWarning=false/>
		</#if> <#--common.methodPresent("Subscribe")-->
		<#if common.methodPresent("Unsubscribe")>
			<@ConstraintViolation iConstraint=constraintDescription("a6(1)", "Unsubscribe") iWarning=false/>
		</#if> <#--common.methodPresent("Unsubscribe")-->
		<#if common.methodPresent("PublishEvent")>
			<@ConstraintViolation iConstraint=constraintDescription("a6(1)", "PublishEvent") iWarning=false/>
		</#if> <#--common.methodPresent("PublishEvent")-->
	</#if><#--names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0"-->
</#if> <#-- if object.businessInterfaceDefinition.idref.type != "bod"-->
<#if names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0">
	<#if common.methodPresent("CreateRef")>
		<@ConstraintViolation iConstraint=constraintDescription("a6(1)", "CreateRef") iWarning=false/>
	</#if> <#--common.methodPresent("CreateRef")-->
	<#if common.methodPresent("DeleteRef")>
		<@ConstraintViolation iConstraint=constraintDescription("a6(1)", "DeleteRef") iWarning=false/>
	</#if> <#--common.methodPresent("DeleteRef")-->
	<#-- Also referential integrity tables are not allowed in BaanIV -->
	<#list listTables2() as t>
		<#if t.isReferentialIntegrityTable>
			<@ConstraintViolation iConstraint=constraintDescription("a7(1)", t.tableName) iWarning=false/>
		</#if><#--if t.isReferentialIntegrityTable-->	
	</#list><#--list listTables2() as t-->
</#if><#--names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0"-->
<#if common.methodPresent("Show")>
	<#if common.methodPresent("List") && protected.hasMethodAlternativeImplementation("List")!=""
			&& protected.hasMethodAlternativeImplementation("Show")=="">
		<@ConstraintViolation iConstraint=constraintDescription("a1(3)", "Show", "List")/>
	</#if> <#--!common.methodPresent("List")-->
</#if> <#--common.methodPresent("Show")-->
<#if common.methodPresent("List")>
	<#if !common.methodPresent("Show") || protected.hasMethodAlternativeImplementation("Show")!="">
		<@ConstraintViolation iConstraint=constraintDescription("a1(3)", "List", "Show")/>
	</#if> <#--!common.methodPresent("List")-->
</#if> <#--common.methodPresent("Show")-->
<#if common.bdeHasMoreThanOneComponent()>
	<#if common.methodPresent("Change")>
		<#if !common.methodPresent("Create")>
			<@ConstraintViolation iConstraint=constraintDescription("a2(2)", "Change", "Create")/>
		</#if> <#--!common.methodPresent("Create")-->
		<#if !common.methodPresent("Delete")>
			<@ConstraintViolation iConstraint=constraintDescription("a2(2)", "Change", "Delete")/>
		</#if> <#-- !common.methodPresent("Create")-->
	</#if> <#--common.methodPresent("Change")-->
	<#if common.methodPresent("Delete")>
		<#if !common.methodPresent("Show")>
			<@ConstraintViolation iConstraint=constraintDescription("a2(2)", "Delete", "Show")/>
			<#-- Show method is used to do delete for subcomponents -->
		</#if> <#--!common.methodPresent("Show")-->
		<#if !common.methodPresent("Change")>
			<@ConstraintViolation iConstraint=constraintDescription("a2(2)", "Delete", "Change")/>
			<#-- Change method is used to do delete for subcomponents -->
		</#if> <#--!common.methodPresent("Show")-->
	</#if> <#--common.methodPresent("Delete")-->
</#if> <#--common.bdeHasMoreThanOneComponent()-->
<#--=========================== METHOD CONSTRAINTS: Alternative implementation ===========================-->
<#if common.methodPresent("Change")>
	<#if protected.hasMethodAlternativeImplementation("Create")!="">
		<@ConstraintViolation iConstraint=constraintDescription("a5(1)", "Change", "Create") iWarning=false/>
	</#if>
	<#if protected.hasMethodAlternativeImplementation("Delete")!="">
		<@ConstraintViolation iConstraint=constraintDescription("a5(1)", "Change", "Delete") iWarning=false/>
	</#if>
</#if>
<#if common.methodPresent("Create")>
	<#if protected.hasMethodAlternativeImplementation("Change")!="">
		<@ConstraintViolation iConstraint=constraintDescription("a5(1)", "Create", "Change") iWarning=false/>
	</#if>
	<#if protected.hasMethodAlternativeImplementation("Delete")!="">
		<@ConstraintViolation iConstraint=constraintDescription("a5(1)", "Create", "Delete") iWarning=false/>
	</#if>
</#if>
<#if common.methodPresent("Delete")>
	<#if protected.hasMethodAlternativeImplementation("Change")!="">
		<@ConstraintViolation iConstraint=constraintDescription("a5(1)", "Delete", "Change") iWarning=false/>
	</#if>
	<#if protected.hasMethodAlternativeImplementation("Create")!="">
		<@ConstraintViolation iConstraint=constraintDescription("a5(1)", "Delete", "Create") iWarning=false/>
	</#if>
</#if>
<#list protected.listProtectedComponents() as c>
	<#list c.componentImplementation.methodImplementation as methodImplementation>
		<#assign methodName = common.getNameFromMethodImplementation(methodImplementation)/>
		<#if c.componentName != names.businessInterfaceName>
			<#if !common.methodPresent(methodName, object.componentImplementation)>
				<#-- Method does not exist in top-level component -->
				<#--#TODO Check is incomplete: violation must also be reported if method exists on level 1 and 3 but not on level 2-->
				<@ConstraintViolation iConstraint=constraintDescription("a3(2)", methodName, c.componentName)/>
			</#if> <#--!common.methodPresent(methodName, names.businessInterfaceName-->
		</#if> <#--c.componentName != names.businessInterfaceName-->
<#--=========================== METHOD CONSTRAINTS: Method Argument Scope ===========================-->
		<#if methodName=="Create" || methodName=="Change" || methodName=="Delete" || methodName=="List" || methodName=="Show" || methodName=="PublishEvent">
			 <#list common.listMethodArgumentImplementations(methodName) as mai>
				<#if mai.attributeImplementation?exists>
					<#assign attributeName=mai.attributeImplementation.idref.name>
					<#assign aiReadOnly=mai.attributeImplementation.idref.isReadOnly>
				<#else>
					<#assign attributeName="">
					<#assign aiReadOnly=false>
				</#if>
				<#if !aiReadOnly>
					<#switch mai.scope>
						<#case "in">
							<#switch methodName>
								<#case "List">
									<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
								<#break>
								<#case "Show">
									<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
								<#break>
							</#switch> <#--methodName-->
						<#break>
						<#case "out">
							<#switch methodName>
								<#case "Change">
									<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
								<#break>
								<#case "Delete">
									<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
								<#break>
								<#case "PublishEvent">
									<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
								<#break>
							</#switch> <#--methodName-->
						<#break>
						<#case "inout">
							<#switch methodName>
								<#case "Delete">
									<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
								<#break>
								<#case "List">
									<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
								<#break>
								<#case "Show">
									<#if mai.attributeImplementation?exists && !mai.attributeImplementation.idref.isIdentifier>
										<@ConstraintViolation iConstraint=constraintDescription("b2(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
									</#if> <#--mai.attributeImplementation?exists && !mai.attributeImplementation.idref.isIdentifier-->
									<#-- For each method argument of Show method except identifying attributes of top-level component: scope must be 'out'; for identifying attributes of top-level component scope must be 'inout'-->
									<#-- However, we should not check on c.componentName!=names.businessInterfaceName, because that would not be ok for child components-->
									<#-- Anyway, we don't use those implementations on child components!-->
								<#break>
								<#case "PublishEvent">
									<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
								<#break>
							</#switch> <#--methodName-->
						<#break>
						<#case "unknown">
							<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
						<#break>
						<#default> <#--case "return"-->
							<@ConstraintViolation iConstraint=constraintDescription("b1(4)", mai.scope, attributeName, methodName, c.componentName) iDetails=mai.id iWarning=true/>
						<#break>
					</#switch> <#--mai.scope-->
				</#if><#--if !aiReadOnly-->
<#--=========================== METHOD CONSTRAINTS: Controlling Attributes ===========================-->
				<#if mai.methodArgument?exists && mai.methodArgument.idref?exists && mai.methodArgument.idref.type=="controllingAttribute">
					<@ConstraintViolation iConstraint=constraintDescription("c1(3)", methodName, c.componentName, mai.methodArgument.value)/>
				</#if> <#--mai.methodArgument?exists && mai.methodArgument.idref.type=="controllingAttribute"-->
				<#if mai.methodArgument?exists && mai.methodArgument.idref?exists && mai.methodArgument.idref.type=="qualifier">
					<@ConstraintViolation iConstraint=constraintDescription("c2(3)", methodName, c.componentName, mai.methodArgument.value)/>
				</#if> <#--mai.methodArgument?exists && mai.methodArgument.idref.type=="qualifier"-->
			 </#list> <#--common.listMethodArgumentImplementations(methodName)-->
		<#else> <#--methodName=...-->
			 <#list common.listMethodArgumentImplementations(methodName) as mai>
				<#if mai.methodArgument?exists && mai.methodArgument.idref.type=="controllingAttribute">
					<@ConstraintViolation iConstraint=constraintDescription("c1(3)", methodName, c.componentName, mai.methodArgument.value)/>
				</#if> <#--mai.methodArgument?exists && mai.methodArgument.idref.type=="controllingAttribute"-->
				<#if mai.methodArgument?exists && mai.methodArgument.idref.type=="qualifier">
					<@ConstraintViolation iConstraint=constraintDescription("c2(3)", methodName, c.componentName, mai.methodArgument.value)/>
				</#if> <#--mai.methodArgument?exists && mai.methodArgument.idref.type=="qualifier"-->
			 </#list> <#--common.listMethodArgumentImplementations(methodName)-->
		</#if> <#--methodName=...-->
<#--=========================== METHOD CONSTRAINTS: Processing Order ===========================-->
		<#switch methodImplementation.processingOrder>
			<#case "topDown">
				<#switch methodName>
					<#case "Delete">
						<@ConstraintViolation iConstraint=constraintDescription("d1(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
					<#break>			
	  				<#case "SubscribeEvent">
						<#if object.businessInterfaceDefinition.idref.type != "bod">
							<@ConstraintViolation iConstraint=constraintDescription("d2(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
						</#if> <#-- if object.businessInterfaceDefinition.idref.type != "bod"-->				
					<#break>
	  				<#case "SubscribeList">
						<#if object.businessInterfaceDefinition.idref.type != "bod">
							<@ConstraintViolation iConstraint=constraintDescription("d2(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
						</#if> <#-- if object.businessInterfaceDefinition.idref.type != "bod"-->
					<#break>
	  				<#case "PublishEvent">
						<@ConstraintViolation iConstraint=constraintDescription("d2(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
					<#break>
	  				<#case "OnEvent">
						<@ConstraintViolation iConstraint=constraintDescription("d2(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
					<#break>
				</#switch> <#--methodName-->
			<#break>
			<#case "bottomUp">
				<#switch methodName>
					<#case "Create">
						<@ConstraintViolation iConstraint=constraintDescription("d1(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
					<#break>
	  				<#case "SubscribeEvent">
						<#if object.businessInterfaceDefinition.idref.type != "bod">
							<@ConstraintViolation iConstraint=constraintDescription("d2(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
						</#if> <#-- if object.businessInterfaceDefinition.idref.type != "bod"-->
					<#break>
	  				<#case "SubscribeList">
						<#if object.businessInterfaceDefinition.idref.type != "bod">
							<@ConstraintViolation iConstraint=constraintDescription("d2(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
						</#if> <#-- if object.businessInterfaceDefinition.idref.type != "bod"-->
					<#break>
	  				<#case "PublishEvent">
						<@ConstraintViolation iConstraint=constraintDescription("d2(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
					<#break>
	  				<#case "OnEvent">
						<@ConstraintViolation iConstraint=constraintDescription("d2(3)", methodName, c.componentName, methodImplementation.processingOrder) iWarning=true/>
					<#break>
				</#switch> <#--methodName-->
			<#break>
			<#case "batch">
				<#switch methodName>
	  				<#case "List">
	  				<#case "Show">
						<#if common.queryMethodPresent()>
							<#-- this means List is batch but Show isn't or the other way around-->
							<#-- (blocking error, because resulting code won't generate: duplicate functions in sb) -->
							<@ConstraintViolation iConstraint=constraintDescription("d4(2)", methodName, c.componentName) iWarning=false/>
						</#if> <#--!methodImplementation.onExecuteHook?exists-->
						<#-- FALL THROUGH! -->
					<#case "Create">
	  				<#case "Change">
	  				<#case "Delete">
						<#if !methodImplementation.onExecuteHookExpression?exists || !methodImplementation.onExecuteHookExpression?has_content>
							<@ConstraintViolation iConstraint=constraintDescription("d3(2)", methodName, c.componentName)/>
						</#if> <#--!methodImplementation.onExecuteHookExpression?exists && !methodImplementation.onExecuteHookExpression?has_content-->
					<#break>
					<#--#TODO What about other standard methods? (CreateRef, DeleteRef, SupportsReferentialIntegrity, SupportsProcessingScope)-->
				</#switch> <#--methodName-->
			<#break>
		</#switch> <#--methodImplementation.processingOrder-->
<#--=========================== METHOD CONSTRAINTS: Implementations on Subcomponents ===========================-->
		<#if c.componentName != names.businessInterfaceName>
			<#switch methodName>
 				<#case "SubscribeList">
					<#if object.businessInterfaceDefinition.idref.type != "bod">
						<@ConstraintViolation iConstraint=constraintDescription("e1(2)", methodName, c.componentName) iWarning=true/>
					</#if> <#-- if object.businessInterfaceDefinition.idref.type != "bod"-->
				<#break>
 				<#case "SubscribeEvent">
					<#if object.businessInterfaceDefinition.idref.type != "bod">
 						<@ConstraintViolation iConstraint=constraintDescription("e2(2)", methodName, c.componentName) iWarning=true/>
					</#if> <#-- if object.businessInterfaceDefinition.idref.type != "bod"-->
				<#break>
 				<#case "PublishEvent">
 				<#case "OnEvent">
					<@ConstraintViolation iConstraint=constraintDescription("e2(2)", methodName, c.componentName) iWarning=true/>
				<#break>
				<#--#TODO temporarily disabled List/Show checks. Method argument implementations are used. Hooks etc. are not. Needs clarification or a more detailed check.
				<#case "List">
					<@ConstraintViolation iConstraint=constraintDescription("e1(2)", methodName, c.componentName) iWarning=true/>
				<#break>
				<#case "Show">
					<@ConstraintViolation iConstraint=constraintDescription("e1(2)", methodName, c.componentName) iWarning=true/>
				<#break>
				-->
			</#switch> <#--methodName-->
			<#if methodImplementation.processingOrder=="batch">
				<@ConstraintViolation iConstraint=constraintDescription("e2(2)", methodName, c.componentName) iDetails=c.componentName+"."+methodName iWarning=true/>
			</#if> <#--methodImplementation.processingOrder="batch"-->
		<#else> <#--c.componentName != names.businessInterfaceName-->
			<#if methodName=="List" || methodName=="Show">
				<#if methodImplementation.onExecuteHookExpression?exists && methodImplementation.onExecuteHookExpression?has_content && methodImplementation.processingOrder?exists && methodImplementation.processingOrder != "batch">
					<@ConstraintViolation iConstraint=constraintDescription("e3(2)", methodName, c.componentName) iWarning=true/>
				</#if> <#--if methodImplementation.onExecuteHookExpression?exists && methodImplementation.onExecuteHookExpression?has_content && methodImplementation.processingOrder?exists && methodImplementation.processingOrder != "batch"-->
			</#if> <#--methodName=="List" || methodName=="Show"-->
		</#if> <#--c.componentName != names.businessInterfaceName-->
	</#list> <#--c.componentImplementation.methodImplementation as methodImplementation-->
<#--=========================== ACTION TYPE CONSTRAINTS: actionType ===========================================-->
	<#-- actionType constraints -->
	<#list c.componentImplementation.methodImplementation as methodImplementation>
		<#assign attributeImplementation=common.getAttributeImplementationActionType(methodImplementation, c.componentImplementation)/>
		<#if attributeImplementation!="">
			<#assign methodName=common.getNameFromMethodImplementation(methodImplementation)/>
			<#switch methodName>
				<#case "Change">
					<#assign datatype=common.getDatatype(attributeImplementation)/>
					<#if common.hasEnumerations(datatype)>
						<#list datatype.facet as facet>
							<#if !common.isStandardActionType(facet.value)>
								<@ConstraintViolation iConstraint=constraintDescription("g2(3)", methodName, c.componentName, facet.value) iWarning=true/>
							</#if>
						</#list>
					<#else>
						<@ConstraintViolation iConstraint=constraintDescription("g3(3)", methodName, c.componentName, datatype.name) iWarning=true/>
					</#if>
				<#case "PublishEvent">
				<#case "OnEvent">
	   				<#break>
	   			<#default>
					<@ConstraintViolation iConstraint=constraintDescription("g1(2)", methodName, c.componentName) iWarning=true/>
					<#break>
			</#switch><#--methodName-->
		</#if>
	</#list> <#--c.componentImplementation.methodImplementation as methodImplementation-->
<#--=========================== COMPONENT/ATTRIBUTE/TABLE CONSTRAINTS: Aggregations ===========================-->
	<#if c.parentComponentName!="">
		<#if c.relationshipImplementation.relationshipImplementationAttribute?exists>
		<#--#TODO or: if c.relationshipImplementation?exists && c.relationshipImplementation.relationshipImplementationAttribute?exists-->
			<#list c.relationshipImplementation.relationshipImplementationAttribute as ria>
				<#--if c.parentComponentImplementation.componentImplementationTable?exists && c.componentImplementation.componentImplementationTable?exists-->
				<#--This 'if' doesn't work: for some reason it always evaluates to true, even if no ComponentImplementationTable exists anywhere in the BI-->
				<#--So we use two list statements including breaks as a work-around:-->
				<#list c.parentComponentImplementation.componentImplementationTable as pct>
					<#list c.componentImplementation.componentImplementationTable as cct>
						<#if !ria.from.idref?exists>
							<@ConstraintViolation iConstraint=constraintDescription("k5(3)", ria.from.value, c.parentComponentName, c.componentName) iWarning=false/>
						<#else>
							<#if !ria.to.idref?exists>
								<@ConstraintViolation iConstraint=constraintDescription("k5(3)", ria.to.value, c.parentComponentName, c.componentName) iWarning=false/>
							<#else>
								<#if !ria.from.idref.isIdentifier || ria.from.idref.type!="column">
									<@ConstraintViolation iConstraint=constraintDescription("k2(3)", ria.from.value, c.parentComponentName, c.componentName)/>
								<#else>
									<#if !ria.to.idref.isIdentifier || ria.to.idref.type!="column">
										<@ConstraintViolation iConstraint=constraintDescription("k2(3)", ria.to.value, c.parentComponentName, c.componentName) iDetails="Issue on child component"/>
									</#if>
								</#if>
							</#if>
						</#if>
						<#break/>
					</#list> <#--c.componentImplementation.componentImplementationTable as cct-->
					<#break/>
				</#list> <#--c.parentComponentImplementation.componentImplementationTable as pct-->
			</#list> <#--c.relationshipImplementation.relationshipImplementationAttribute as ria-->
		<#else>
			<@ConstraintViolation iConstraint=constraintDescription("k1(1)", c.componentName)/>
		</#if> <#--!c.relationshipImplementation.RelationshipImplementationAttribute?exists-->
		<#if c.parentComponentImplementation.componentImplementationTable?exists>
			<#list c.parentComponentImplementation.attributeImplementation as pai>
				<#if pai.isIdentifier && pai.type=="column">
					<#assign isUsedInFrom=false>
					<#list c.relationshipImplementation.relationshipImplementationAttribute as ria>
						<#if !ria.from.idref?exists>
							<@ConstraintViolation iConstraint=constraintDescription("k5(3)", ria.from.value, c.parentComponentName, c.componentName) iWarning=false/>
						<#else>
							<#if ria.from.idref.name==pai.name>
								<#assign isUsedInFrom=true>
								<#break/>
							</#if> <#--ria.from.idref.name==pai.name-->
						</#if>
					</#list> <#--c.relationshipImplementation.relationshipImplementationAttribute as ria-->
					<#if !isUsedInFrom>		
						<#--pai does not occur as 'from' in RelationshipImplementation-->
						<@ConstraintViolation iConstraint=constraintDescription("k3(3)", c.componentName, pai.name, c.parentComponentName)/>
					</#if>
				</#if> <#--pai.isIdentifier && pai.type=="column"-->
			</#list> <#--c.parentComponentImplementation. as pai-->
		</#if>
	</#if> <#--c.parentComponentName!=""-->
	<#if common.queryMethodPresent()>
		<#assign AFSComponentPresent=false>
		<#list protected.listProtectedComponents() as pc>
			<#if protected.isFunctionServerComponent(pc.componentImplementation)>
				<#assign AFSComponentPresent=true>
				<#break>
			</#if>
		</#list>
		<#if !AFSComponentPresent>
			<#list protected.listProtectedAssociatedAttributes(c.componentImplementation) as aa>
				<#if !aa.toBusinessInterfaceImplementation.implementationIdentifier?exists>
					<@ConstraintViolation iConstraint=constraintDescription("k4(2)", "${names.businessInterfaceName}.${aa.fromComponentName}.${aa.fromAttributeName}", "${aa.toBusinessInterfaceName}") iWarning=false/>
				</#if>
			</#list>
		</#if>
	</#if>
</#list> <#--protected.listProtectedComponents() as c-->
<#--=========================== METHOD CONSTRAINTS: Required Table Mappings ===========================-->
<#assign biiHasAnyTableMapping=false/>
<#list protected.listProtectedComponents() as c>
	<#if c.componentImplementation.componentImplementationTable?exists>
		<#assign biiHasAnyTableMapping=true/>
	</#if> <#--c.componentImplementation.componentImplementationTable?exists-->
</#list> <#--protected.listProtectedComponents() as c-->
<#if !biiHasAnyTableMapping && (common.methodPresent("List") || common.methodPresent("Show"))>
	<@ConstraintViolation iConstraint=constraintDescription("f1(0)")/>
</#if>
<#--=========================== METHOD CONSTRAINTS: Required Protected method arguments ===========================-->
<#list protected.listProtectedComponents() as c>
	<#list ["List", "Show"] as methodName>
		<#if common.protectedMethodPresent(methodName, c.componentImplementation)>
			<#list common.listAttributeImplementations(c.componentName) as ai>
				<#if common.getIsIdentifier(ai.attributeImplementation)>
					<#assign found=false>
					<#list protected.listProtectedAttributes(methodName, c.componentName) as a>
						<#if a.attributeName==ai.attributeName>
							<#assign found=true>
							<#break>
						</#if>
					</#list>
					<#if found==false>
						<@ConstraintViolation iConstraint=constraintDescription("r1(3)", ai.attributeName, methodName, c.componentName)/>
					</#if>
				</#if>
			</#list>
		</#if>
	</#list>
</#list>
<#-- This check will report mandatory attributes in query method, which are not. present in the relation to its parent. -->
<#list protected.listProtectedComponents() as c>
	<#list ["List", "Show"] as methodName>
		<#if common.protectedMethodPresent(methodName)>
			<#if c.parentComponentName!="">
				<#list c.componentImplementation.methodImplementation as cm>
					<#if cm.name==methodName>
						<#list cm.methodArgumentImplementation as ma>
							<#if ma.isMandatory>
								<#assign allowed=false>
								<#if c.relationshipImplementation.relationshipImplementationAttribute?exists>
									<#list c.relationshipImplementation.relationshipImplementationAttribute as ria>
								<#if ria.to.idref == ma.attributeImplementation.idref>
									<#assign allowed=true>
								</#if>
									</#list>	
								</#if>
								<#if !allowed>
									<@ConstraintViolation iConstraint=constraintDescription("r1(4)", ma.name, methodName, c.componentName)/>
								</#if>
							</#if>
						</#list>
					</#if>
				</#list>
			</#if>
		</#if>
	</#list>
</#list>
<#--=========================== COMPONENT/ATTRIBUTE/TABLE CONSTRAINTS: Identifiers ===========================-->
<#function listImplementationAttributesForColumn iComponentImplementation iTableName iColumnName>
	<#local container=[]/>
	<#list iComponentImplementation.attributeImplementation as ai>
		<#if ai.type=="column" && ai.componentImplementationTable.idref.table.value==iTableName && ai.column.value==iColumnName>
			<#local container=container+[ai]/>
		</#if>
	</#list>
	<#return container/>
</#function>
<#list listTables2() as t> <#--#TODO #list protected.listTables() as t-->
	<#if !t.isReferentialIntegrityTable && t.isRootTable>
			<#list t.table.column as c>
				<#if c.isPrimaryKey>
					<#assign columnIsUsedInIdentifier=false/>
					<#list listImplementationAttributesForColumn(t.componentImplementation, t.tableName, c.name) as aic>
						<#if aic.isIdentifier?exists && aic.isIdentifier>
							<#assign columnIsUsedInIdentifier=true/>
						</#if>
					</#list>
					<#if !columnIsUsedInIdentifier>
						<@ConstraintViolation iConstraint=constraintDescription("m1(3)", t.tableName, c.name, t.componentImplementation.component.value)/>
						<#--For each key column of table, it must be mapped to an identifying attribute implementation of the component that uses the table as its root table.-->
					</#if> <#--!columnIsUsedInIdentifier-->
				</#if><#--if c.isPrimaryKey-->
			</#list><#--list t.table.column as c-->
		</#if><#--if !t.isReferentialIntegrityTable && t.isRootTable-->	
	</#list><#--list protected.listTables() as t-->
<#--=========================== COMPONENT/ATTRIBUTE/TABLE CONSTRAINTS: Data Types ===========================-->
<#list protected.listProtectedComponents() as c>
	<#list c.componentImplementation.attributeImplementation as ai>
		<#assign aiDatatype=common.getDatatypeFromAttributeImplementation(ai)>
		<#if aiDatatype="">
			<@ConstraintViolation iConstraint=constraintDescription("n6(2)", c.componentImplementation.component.value, ai.name)/>		
		<#else>
			<#if ai.type=="column">
				<#if ai.datatype?exists && ai.datatype!="" && !ai.additionalInstructions?exists>
					<@ConstraintViolation iConstraint=constraintDescription("n2(2)", c.componentImplementation.component.value, ai.name)/>
				</#if>
				<#if aiDatatype.dimensions?exists>
					<#assign dimensions=aiDatatype.dimensions>
					<#if dimensions?has_content && dimensions?contains(",")>    
						<@ConstraintViolation iConstraint=constraintDescription("n4(3)", dimensions, c.componentImplementation.component.value, ai.name)/>
					<#else>			
						<#assign tableDimensions=ai.column.idref.datatype.idref.dimensions>
						<#if !(dimensions == tableDimensions)>
							<@ConstraintViolation iConstraint=constraintDescription("n5(4)", tableDimensions, dimensions, c.componentImplementation.component.value, ai.name)/>
						</#if><#--!(dimensions == tableDimensions)-->
					</#if><#--dimensions?has_content && dimensions?contains(",")--> 
				</#if><#--ai.datatype?exists && ai.datatype.idref.dimensions?exists-->
			</#if> <#--ai.type=="column"-->
			<#if !aiDatatype.nativeDatatype?exists || aiDatatype.nativeDatatype=="">
				<@ConstraintViolation iConstraint=constraintDescription("n1(3)", aiDatatype.name, c.componentImplementation.component.value, ai.name)/>
				<#--Datatype "+iArg1+" of attribute implementation "+iArg2+"."+iArg3+" must have a native data type specified.-->
			<#else>
				<#-- <#if ...(ai.datatype.idref.nativeDatatype)> #TODO
					<@ConstraintViolation iConstraint=constraintDescription("n3(2)", c.componentImplementation.component.value, ai.name)/>
					A used native data type must always be a domain. How can we check this?
					We could check for example less than 2 characters or more than ... characters). But that is insufficient.
					We could also check whether the native data type contains any upper case characters.
					Anyhow, the most important thing is having the native data type filled in the first place.
				</#if>
				-->
			</#if>
		</#if>
	</#list> <#--c.componentImplementation.attributeImplementation as ai-->
</#list> <#--protected.listProtectedComponents() as c-->
<#--=========================== COMPONENT/ATTRIBUTE/TABLE CONSTRAINTS: Non-Root Tables ===========================-->
<#--
Constraints on non-root tables:
(o1) Cycles and self references are not allowed between tables
(o2) Tables within one component should be related with each other
(o3) All identifiers of all non-root tables have to occur as attribute implementation on the component
-->
<#list protected.listProtectedComponents() as c>
	<#-- check (o1) and (o2) via function checkTableStructureOfComponent -->
	<#assign check = checkTableStructureOfComponent(c)>
	<#if !check.cycleFree>
		<@ConstraintViolation iConstraint=constraintDescription("o1(1)", c.componentImplementation.component.value) iWarning=true/>
	</#if>
	<#if !check.coherent>
		<@ConstraintViolation iConstraint=constraintDescription("o2(1)", c.componentImplementation.component.value) iWarning=true/>
	</#if>
	<#-- check all non-root tables for (o3) -->
	<#list c.componentImplementation.componentImplementationTable as cit>
		<#if !cit.isRootTable>
			<#list cit.table.idref.column as col>
				<#if col.isPrimaryKey>
					<#if !isColumnLinkedToAttributeImplementation(cit.table.idref.name, col.name, c)>
						<@ConstraintViolation iConstraint=constraintDescription("o3(3)", col.name, cit.table.idref.name, c.componentImplementation.component.value) iWarning=false/>
					</#if>
				</#if>
			</#list>
		</#if>
	</#list><#--list c.componentImplementation.componentImplementationTable as cit-->
</#list> <#--list protected.listProtectedComponents() as c-->

<#--=========================== COMPONENT/ATTRIBUTE/TABLE CONSTRAINTS: Attribute Grouping ===========================-->
<#-- #TODO
Attribute grouping:
(p1) If one attribute from a group is mandatory then the group must also be mandatory.
(p2) If an attribute group is mandatory it must contain at least one mandatory attribute.
(p3) If an attribute group is read-only then all its children must be read-only.
-->

<#--=========================== COMPONENT/ATTRIBUTE/TABLE CONSTRAINTS: Components ===========================-->
<#-- Constraints on components:
(q1) No duplicate component names are allowed
-->
<#assign duplicateComponents=[]/>
<#list protected.listProtectedComponents() as c>
	<#list protected.listProtectedComponents() as ci>
		<#if c.componentImplementation!=ci.componentImplementation>
			<#if c.componentImplementation.component.idref.name==ci.componentImplementation.component.idref.name>
				<#assign duplicate=false>
				<#list duplicateComponents as dc>
					<#if dc==c.componentImplementation.component.idref.name>
						<#assign duplicate=true>
						<#break>
					</#if>
				</#list>
				<#if duplicate==false>
					<#assign duplicateComponents=duplicateComponents+[c.componentImplementation.component.idref.name]>			
				</#if>
			</#if>
		</#if>
	</#list>
</#list>
<#list duplicateComponents as dc>
	<@ConstraintViolation iConstraint=constraintDescription("q1(1)", dc) iWarning=false/>
</#list>

<#--=========================== GENERAL CONSTRAINTS	===========================-->

<#-- Allowed now.
<#if protected.generateFunctionServer()>
	<@ConstraintViolation iConstraint=constraintDescription("x1(0)")/>
</#if> <#--protected.generateFunctionServer()-->

<#if (names.businessInterfaceName?length>40)>
	<@ConstraintViolation iConstraint=constraintDescription("x2(1)", names.businessInterfaceName)/>
</#if>
<#if object.businessInterfaceDefinition.idref.type == "bod">
	<#if object.visibility=="public" && object.name != object.businessInterfaceDefinition.idref.name+"BOD">
		<@ConstraintViolation iConstraint=constraintDescription("x3(2)", object.name, object.businessInterfaceDefinition.idref.name) iWarning=false/>
	</#if>
	<#list object.businessInterfaceDefinition.idref.event as event>
		<#switch event.name>
		<#case "Process">
		<#case "Acknowledge">
		<#case "Sync">
		<#case "Load">
		<#case "Post">
		<#case "Update">
			<#break>
		<#case "Get">
		<#case "Show">
			<#if event.canBeReceived || event.canBePublished>
				<@ConstraintViolation iConstraint=constraintDescription("x6(1)", event.name)/>
			</#if>
			<#break>
		<#case "Confirm">
			<#if event.canBeReceived>
				<@ConstraintViolation iConstraint=constraintDescription("x7(1)", event.name)/>
			</#if>
			<#break>
		<#default>
			<#if event.canBeReceived || event.canBePublished>
				<@ConstraintViolation iConstraint=constraintDescription("x5(1)", event.name)/>
			</#if>
			<#break>
		</#switch><#--switch event.name-->
	</#list>
<#else>
	<#--Constraint: no events should be modeled for BDE BIDs-->
	<#list object.businessInterfaceDefinition.idref.event as event>
		<@ConstraintViolation iConstraint=constraintDescription("x4(1)", event.name)/>
	</#list>
</#if>
<#--=========================== Loop detection in calculated attributes ===========================-->
<#assign chainLoop=[]>

<#function ReadAttributeRelations iai iongethooks>
	<#if iongethooks && iai.onGetHookExpression?exists && iai.onGetHookExpression != "" ||
		!iongethooks && iai.onSetHookExpression?exists && iai.onSetHookExpression != ""> 
		<#list chainLoop as cL>
			<#if iai.name == cL.name>
				<#assign chainLoop=chainLoop+[{"name":iai.name}]>
				<#return true>
			</#if>
		</#list>
		<#assign chainLoop=chainLoop+[{"name":iai.name}]>
		<#list iai.attributeImplementationRelationship as air>
			<#if ReadAttributeRelations(air.attributeImplementation.idref, iongethooks)>
				<#return true>
			</#if>
		</#list>
	</#if>
	<#return false>
</#function>

<#list protected.listProtectedComponents() as c>
	<#list c.componentImplementation.attributeImplementation as ai>
		<#assign chainLoop=[]>
		<#if ReadAttributeRelations(ai, true)>
			<#assign loop="">
			<#list chainLoop as cL>
				<#if loop=="">
					<#assign loop=cL.name>
				<#else>
					<#assign loop=loop + "->" + cL.name>
				</#if>
			</#list>
			${logger.error(object, "Loop detected in Used Attributes:" + loop)}
		</#if>
		<#assign chainLoop=[]>
		<#if ReadAttributeRelations(ai, false)>
			<#assign loop="">
			<#list chainLoop as cL>
				<#if loop=="">
					<#assign loop=cL.name>
				<#else>
					<#assign loop=loop + "->" + cL.name>
				</#if>
			</#list>
			${logger.error(object, "Loop detected in Used Attributes:" + loop)}
		</#if>
	</#list>
</#list>

<#--=========================== Conversion hooks on protected attributes ==========================-->
<#list protected.listProtectedAttributes("") as pa>
	<#if pa.attributeImplementation.conversionGetHookExpression?exists && !pa.attributeImplementation.attribute?exists>
		<@ConstraintViolation iConstraint=constraintDescription("s1(3)", "Get", pa.componentName, pa.attributeName) iWarning=true/>
	</#if>
	<#if pa.attributeImplementation.conversionSetHookExpression?exists && !pa.attributeImplementation.attribute?exists>
		<@ConstraintViolation iConstraint=constraintDescription("s1(3)", "Set", pa.componentName, pa.attributeName) iWarning=true/>
	</#if>
</#list>

<#--=========================== #TODO NOTES/EXTENSIONS ===========================-->
<#--Constraint: if standard conversion is applicable (UTC, boolean, enum, text) then public data type must be ok for that conversion, unless a conversion hook is specified-->
<#--Constraint: if no standard conversion is applicable then public data type must match the native data type (domain), unless a conversion hook is specified-->
<#--Constraint: sequence of identifying attributes in PublishChanges arguments must match sequence of identifying attributes in Show arguments (for each component?)-->
<#--Constraint: MethodImplementation.implementationModule and MethodImplementation.implementationProcedure are unused for ERP LN-->
<#--Constraint: If no referential integrity table exists but a CreateRef or DeleteRef is implemented without an on execute hook: raise an exception!-->
<#--Constraint: In case a non-root table is used, there must be a reference from the non-root to the root (not the other way around)-->
</#compress>