<#--
   ******************************************************
   *
   *                       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.
   *
   ******************************************************
  -->

<#if common.publishMethodPresent()>
|* ****** Synchronization parts *********************************************

	long	bl.pub.request
	long	bl.pub.response
	long	bl.pub.result

function extern long <@names.ST_DLLCode/>.set.PublishRequest(
					long	i.value)
{
	DllUsage
	EndDllUsage

	bl.pub.request = i.value

	return (0)
}

function extern long <@names.ST_DLLCode/>.get.PublishResponse(
				ref long	o.value)
{
	DllUsage
	EndDllUsage

	o.value = bl.pub.response

	return (0)
}

function extern long <@names.ST_DLLCode/>.get.PublishResult(
				ref long	o.value)
{
	DllUsage
	EndDllUsage

	o.value = bl.pub.result

	return (0)
}

function extern long <@names.ST_DLLCode/>.execute.PublishChanges()
{
	DllUsage
	EndDllUsage

	|* Getters/Setters will be passed directly to danch.

	RETIFNOK_SYNC(call.publish.method("danchpublic.publish.changes"))

	return(0)
}

function extern long <@names.ST_DLLCode/>.execute.UnpublishChanges()
{
	DllUsage
	EndDllUsage

	|* Getters/Setters will be passed directly to danch.

	RETIFNOK_SYNC(call.publish.method("danchpublic.unpublish.changes"))

	return(0)
}

function long call.publish.method(const string funname)
{
	static  long    DLLid
		long    funid
		long    funreturn
		long    retval

	if DLLid = 0 then
		DLLid = load_dll("odanchpublic", DLL_SILENT_ERR)
		if DLLid = 0 then
			dal.set.error.message("tlbctst0005", "odanchpublic")
			|* Cannot load Synchronization Object
			return (DALHOOKERROR)
		endif
	endif
	funid = get_function(DLLid, funname)
	if funid > 0 then
		retval = exec_function(DLLid, funid, funreturn, "<<BODesc/>>",
			bl.pub.request, bl.pub.response, bl.pub.result)
	else
		dal.set.error.message("tlbctst0006", strip$(funname))
		|* Cannot execute Synchronization Method!
		return (DALHOOKERROR)
	endif
	return(funreturn)
}
</#if><#-- if common.publishMethodPresent -->

<#--
The following types of external functions are generated for public methods:
1  A query implementation.
   This is used for List/Show (currently always, but should be: unless the method has processingScope 'batch').
   Implemented in public.sb.main.ftl and protected.st.query.ftl.
2  A batch implementation.
   This is used for SubscribeEvent, UnsubscribeEvent, PublishEvent, OnEvent, and all (other) methods having processingScope 'batch' (except List and Show, currently).
   Note: for Create, Change and Delete an 'on execute hook' must be defined, because there is no default 'batch' implementation.
   Implemented in public.sb.events.ftl and protected.st.events.ftl.
   (By the way, naming of 'public.sb.events.ftl' actually is incorrect: contains code used for all batch methods, not just for event publishing).
3  An old-fashioned batch implementation.
   This is used for PublishChanges and UnpublishChanges. (If either PublishList or PublishChanges or UnpublishChanges exists then both are generated.)
   Implemented in public.sb.events.ftl and protected.st.events.ftl.
4  A (more or less) fixed implementation.
   This is used for SupportsReferentialIntegrity
   Implemented in public.sb.main.ftl and protected.st.main.ftl.
5  No implementation
   This is used for subscribeList, PublishList and SupportsProcessingScope.
   These methods are handled in the dispatcher.
6  A normal top-down/bottom-up implementation
   This is used in all other cases (standard methods Create, Change, Delete, CreateRef, DeleteRef, and specific methods)
   Implemented in public.sb.main.ftl and protected.st.methods.ftl (before/execute/after function).
7  Assisting methods for event publishing, if the PublishEvent method exists.
   Implemented in public.sb.events.ftl (GetPublicIdentifiers) and protected.st.events.ftl
   (a number of SetInternalIdentifiers functions, ShowAndPublishEvent for each component, ShowAndPublishStandardEvent for each component).
Open issue: there seems to be some overlap between these categories.

Additionally only in protected layer:
1  A protected Read method per component, implemented in protected.st.methods.ftl.
2  A finalize method (except for publishing and event methods), implemented in protected.st.methods.ftl.
3  Method-independent: before.initialized and get.method.result, implemented in protected.st.methods.ftl.
4  Method-independent: getters and setters in protected.st.main.ftl.
   For refKey (only if CreateRef/DeleteRef exists) and for all attributes.
   Implemented in protected.st.main.ftl.

A batch implementation for the List and Show methods is enabled as follows:
1  Change implementation of common.queryMethodPresent.
2  Change conditions such as if methodName = List or Show.
3  When using protected.st.query.ftl only for non-batch List/Show, we must still generate the following function for PublishEvent even if no 'query method' exists:
   function extern boolean <@names.ST_DLLCode/>.attr.is.calculated() -> no impact, is only called if queryMethodPresent.
-->
<#list protected.listProtectedComponents() as c>
	<#list c.componentImplementation.methodImplementation as methodImplementation>
		<#assign methodName = common.getNameFromMethodImplementation(methodImplementation)>
		<#if methodName != "SubscribeList" && methodName != "SupportsProcessingScope">
			<#if (common.isEventMethod(methodName) || methodImplementation.processingOrder == "batch") && 
				  c.componentName == names.businessInterfaceName &&
			     protected.hasMethodAlternativeImplementation(methodName)=="">
|* ****** Batch method: ${c.componentName}.${methodName} ******

function extern 
long <@names.ST_DLLCode/>.execute.${c.componentName}.${methodName}(
						long	i.request, 
					ref	long	o.response, 
					ref	long	o.result)
{
	DllUsage
	EndDllUsage
				<#if protected.executeMethodHookPresent("before", methodImplementation)>
	boolean	io.cancel
				</#if><#-- if protected.executeMethodHookPresent("before", methodImplementation) -->
				<#if protected.executeMethodHookPresent("on", methodImplementation) || !common.isEventMethod(methodName)>
	boolean	loc.default
					<#if protected.executeMethodHookPresent("on", methodImplementation) && methodName == "SubscribeEvent">
	string	loc.suppressPublisherActions(50)	| 3*6 + 2 + some extra space
					</#if><#--protected.executeMethodHookPresent("on", methodImplementation) && methodName == "SubscribeEvent"-->
				</#if><#-- if protected.executeMethodHookPresent("on", methodImplementation) || !common.isEventMethod(methodName)-->
				<#if common.isEventMethod(methodName)><#-- Only for onevent... -->
	long	loc.metaData
	long	duml
				</#if><#--if common.isEventMethod(methodName)><#-- Only for onevent... -->
				<#if common.isEventMethod(methodName) ||
					protected.executeMethodHookPresent("before", methodImplementation) ||
					protected.executeMethodHookPresent("after", methodImplementation)>
	long	retl
				</#if><#--if common.isEventMethod(methodName) ||
					protected.executeMethodHookPresent("before", methodImplementation) ||
					protected.executeMethodHookPresent("after", methodImplementation) -->

				<#if protected.executeMethodHookPresent("before", methodImplementation)>
	| Reset io.cancel
	io.cancel = false
	retl = Hook.BeforeExecute.${c.componentName}.${methodName}(
					i.request, io.cancel)
					<#if methodName == "PublishEvent">
	if retl <> 0 then
		dal.set.error.message("tlbctstgen", "PublishEvent",
				"${c.componentName}", "${names.businessInterfaceName}")
		|* Error occurred in method '%1$s' on component '%2$s' of object '%3$s'
		| this message will be added to existing result in sb
		if o.response <> 0 then
			duml = xmlDelete(o.response)
			o.response = 0
		endif
	endif
					<#else>
	RETIFNOK(retl)
					</#if>
	if io.cancel then
		| Set result to 0
		o.result = 0

		| Create an empty response
		o.response = xmlNewNode("${methodName}Response", XML_ELEMENT)
		return(0)
	endif
				</#if>
				<#if common.isEventMethod(methodName)>
					<#if protected.executeMethodHookPresent("on", methodImplementation)>

	loc.default = false
						<#if methodName == "SubscribeEvent">
	retl = Hook.OnExecute.${c.componentName}.${methodName}(
			i.request, o.response, o.result, loc.default, loc.suppressPublisherActions)
						<#else>
	retl = Hook.OnExecute.${c.componentName}.${methodName}(
					i.request, o.response, o.result, loc.default)
						</#if><#--methodName == "SubscribeEvent"-->
						<#if methodName == "PublishEvent">
	if retl <> 0 then
		dal.set.error.message("tlbctstgen", "PublishEvent",
				"${c.componentName}", "${names.businessInterfaceName}")
		|* Error occurred in method '%1$s' on component '%2$s' of object '%3$s'
		| this message will be added to existing result in sb
		if o.response <> 0 then
			duml = xmlDelete(o.response)
			o.response = 0
		endif
	endif
						<#else>
	RETIFNOK(retl)
						</#if>
	if loc.default then
					</#if><#--if protected.executeMethodHookPresent("on", methodImplementation)-->
		| Create meta data node containing info on generated library and function name
		retl = tlbct.dll1000.CreateMetaDataNode(
						"<@names.SB_Object/>", "<@names.SB_DLLCode/>.", 
						"<@names.ST_Object/>", "<@names.ST_DLLCode/>.",
					loc.metaData,
					o.result,
						"${object.businessInterfaceDefinition.idref.type}")
					<#if methodName == "PublishEvent">
		if retl <> 0 then
			dal.set.error.message("tlbctstgen", "PublishEvent",
					"${c.componentName}", "${names.businessInterfaceName}")
			|* Error occurred in method '%1$s' on component '%2$s' of object '%3$s'
			| this message will be added to existing result in sb
			if o.response <> 0 then
				duml = xmlDelete(o.response)
				o.response = 0
			endif
		endif
					<#else>
		RETIFNOK(retl)
					</#if>

		| Call the default execute for ${methodName}
					<#if object.businessInterfaceDefinition.idref.type == "bod" && methodName == "PublishEvent">
		retl = tlbct.dll1000.DefaultOnExecute.PublishBOD(
					"${names.businessInterfaceName}",
					"${names.noun}",
					loc.metaData,
					<#else>
		retl = tlbct.dll1000.DefaultOnExecute.${methodName}(
					"${names.businessInterfaceName}",
					loc.metaData,
					</#if><#--object.businessInterfaceDefinition.idref.type == "bod" && methodName == "PublishEvent"-->
					<#if methodName == "SubscribeEvent">
						<#if protected.executeMethodHookPresent("on", methodImplementation)>
					i.request, o.response, o.result,
					loc.suppressPublisherActions)
						<#else>
					i.request, o.response, o.result, "")
						</#if><#--if protected.executeMethodHookPresent("on", methodImplementation)-->
					<#else>
					i.request, o.response, o.result)
					</#if><#--methodName == "SubscribeEvent"-->
		| Cleanup meta data information
		duml = xmlDelete(loc.metaData)
		loc.metaData = 0

					<#if protected.executeMethodHookPresent("on", methodImplementation)>
		return(retl)
	endif
					<#else>
		RETIFNOK(retl)
					</#if><#--if protected.executeMethodHookPresent("on", methodImplementation)-->
				<#else><#--if common.isEventMethod(methodName)-->
	loc.default = false
				<#--Check and report error if no on execute hook exists! For both specific and standard methods.
				    Standard methods must never be batch except for event methods or if on execute hook exists.-->
					<#if (!methodImplementation.onExecuteHookExpression?exists || !methodImplementation.onExecuteHookExpression?has_content)
						&& protected.hasMethodAlternativeImplementation(methodName)=="">
					${logger.error(object, "Batch implementation of method "+methodName+" must have an On Execute Hook defined")}
					</#if>
	RETIFNOK(Hook.OnExecute.${c.componentName}.${methodName}(
					<#if protected.generateIoDefaultInOnExecuteHook(methodName, methodImplementation.processingOrder)>
		i.request, o.response, o.result, loc.default))
					<#else>
		i.request, o.response, o.result))
					</#if><#--if protected.generateIoDefaultInOnExecuteHook(methodName, methodImplementation.processingOrder)-->
				</#if><#--if common.isEventMethod(methodName)-->
				<#if protected.executeMethodHookPresent("after", methodImplementation)>
	retl = Hook.AfterExecute.${c.componentName}.${methodName}(
									i.request, o.response)
					<#if methodName == "PublishEvent">
	if retl <> 0 then
		dal.set.error.message("tlbctstgen", "PublishEvent",
				"${c.componentName}", "${names.businessInterfaceName}")
		|* Error occurred in method '%1$s' on component '%2$s' of object '%3$s'
		| this message will be added to existing result in sb
		if o.response <> 0 then
			duml = xmlDelete(o.response)
			o.response = 0
		endif
	endif
					<#else>
	RETIFNOK(retl)
					</#if>
				</#if>
	return(0)
}	
			</#if><#--if (common.isEventMethod(methodName) || methodImplementation.processingOrder == "batch") && 
				  c.componentName == names.businessInterfaceName &&
			     protected.hasMethodAlternativeImplementation(methodName)==""-->
		</#if><#--if methodName != "SubscribeList" && methodName != "SupportsProcessingScope" -->
	</#list><#-- list c.componentImplementation.methodImplementation as methodImplementation -->
</#list><#-- list protected.listProtectedComponents() as c -->

<#if object.businessInterfaceDefinition.idref.type == "bod">
|------------ GetPublishableEventActions() for all components ------------

function extern long <@names.ST_DLLCode/>.GetPublishableEventActions()
{
DllUsage
	Desc:	Returns a list of all publishable actions
	Return: XML structure containing all publishable verbs
EndDllUsage

	long	publishable.actions
	long	duml
	
	publishable.actions = xmlNewNode("PublishableEventActions")
	<#list ["Sync", "Process", "Load", "Post", "Update", "Get", "Show"] as verb>
		<#if common.eventCanBePublished(verb)>
	duml = xmlNewDataElement("eventAction", "${verb}", publishable.actions)
		</#if><#--if common.eventCanBePublished(verb)-->
	</#list><#--list ["Sync", "Process", "Load", "Post", "Update", "Get"] as verb-->
	
	return(publishable.actions)
}

</#if><#--if object.businessInterfaceDefinition.idref.type == "bod"-->
<#if common.methodPresent("PublishEvent")>
|------------ SetInternalIdentifiers() for all components ------------

function extern long <@names.ST_DLLCode/>.SetInternalIdentifiers(
		long	i.internalData)
{
DllUsage
	This function must only be used by the Tools Add-On package
	or the public layer.
	Do not use it in hook code or other libraries.
	Return value: 0 (OK) or an error value.
	In case of error a dal error message has been set.
EndDllUsage

<#-- Input example for component = Order,
for which the identifier is calculated based on two attribute implementations:
	<Order>
		<orderNumber>1234</orderNumber>
		<orderType>2</orderType>
	</Order>
	(2 means ppmmm.otyp.pur)
Also works for subcomponents, such as OrderLine:
	<OrderLine>
		<orderNumber>1234</orderNumber>
		<orderType>2</orderType>
		<lineNumber>1234</lineNumber>
		<sequenceNumber>2</sequenceNumber>
	</OrderLine>
-->
	string	component.name(${common.CompLen()})
	<#list protected.listProtectedComponents() as c>
		<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
			<#assign domain = common.getDatatypeName(common.getDatatypeFromAttributeImplementation(iai.attributeImplementation))>
	domain  ${domain}  local.${iai.componentName}.${iai.attributeName}
		</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
	</#list><#-- protected.listProtectedComponents() as c -->
	long	attributeNode	| child of instanceNode
	long	retl			| return value to be checked
	long	duml			| dummy variable

	attributeNode = 0
	retl = 0
	duml = 0
	<#-- determine component name -->
	component.name = xmlName$(i.internalData)

	on case component.name
	<#list protected.listProtectedComponents() as c>
	case "${c.componentName}":
		<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
		attributeNode = xmlFindFirstMatch("<${iai.componentName}>.<${iai.attributeName}>",
							i.internalData)
		ERR_IF(attributeNode = 0, "${c.componentName}")
		<#-- now check conversion type) -->
		<#-- need to check value as well before setting? -->
		<#-- #TODO also need to set corresponding values for parent components!? -->

		local.${iai.componentName}.${iai.attributeName} = 
			<#assign backendDatatype = common.get_BaanDatatype_from_XMLSchemaDatatype(common.getDatatype(iai.attributeImplementation))>
			<#switch backendDatatype>
		 		<#case "DB.LONG">
	  			<#case "DB.DATE">
 			 	<#case "DB.TIME">
				lval(xmlData$(attributeNode))
					<#break>
			  	<#case "DB.DOUBLE">
				val(xmlData$(attributeNode))
					<#break>
				<#case "DB.ENUM">
				ltoe(lval(xmlData$(attributeNode)))
				<#break>
			<#default>
				xmlData$(attributeNode)
				<#break>
			</#switch><#-- switch datatype -->
		</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai -->
		retl = <@names.ST_DLLCode/>.${c.componentName}.SetInternalIdentifiers(
		<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
				local.${iai.componentName}.${iai.attributeName},
		</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
					duml)
		ERR_IF(retl <> 0, "${c.componentName}") | incorrect component
		break
	</#list><#-- protected.listProtectedComponents() as c -->
	default:
		ERR_IF(true, component.name) | incorrect component
	endcase

	return(0) | OK
}

	<#list protected.listProtectedComponents() as c>
|------------ SetInternalIdentifiers() for ${c.componentName} ------------
		<#-- Determine root table of component, to be used in query generation later -->
		<#assign rootTableName=""/>
		<#list c.componentImplementation.componentImplementationTable as cit>
			<#if cit.isRootTable>
				<#assign rootTableName=cit.table.idref.name/>
			</#if><#--if !cit.isRootTable -->
		</#list><#--list c.componentImplementation.componentImplementationTable as cit -->

function extern long <@names.ST_DLLCode/>.${c.componentName}.SetInternalIdentifiers(
<#-- Generate input argument for each identifier of table -->
		<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
			<#assign domain = common.getDatatypeName(common.getDatatypeFromAttributeImplementation(iai.attributeImplementation))>
     	domain  ${domain}  i.${iai.attributeName}, 
		</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
		long	i.settings)<#-- currently unused -->
{
DllUsage
	This function must only be used by the Tools Add-On package
	or the public layer.
	Do not use it in hook code or other libraries.
	Return value: 0 (OK) or an error value.
	In case of error a dal error message has been set.
EndDllUsage

<#-- Function has same functionality as comparable function without component name (above),
except that no XML is used, but the input arguments are listed explicitly instead -->

	long	attributeNode	| child of instanceNode

	attributeNode = 0
		<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
	bl.${iai.componentName}.${iai.attributeName} = i.${iai.attributeName}
	bl.${iai.componentName}.${iai.attributeName}.set = true
		</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai -->

	<#if c.parentComponentName != "">
	| Set identifiers for parent components
	</#if>
		<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
			<#list protected.listProtectedParentComponents(c.componentName) as pc>
				<#list common.listRelationshipDetails(pc.componentImplementation, pc.relationshipImplementation) as details>
					<#assign toField=details.toAttributeImplementation.name>
					<#assign fromField=details.fromAttributeImplementation.name>
					<#if toField == iai.attributeName>
	bl.${pc.componentName}.${fromField} = i.${iai.attributeName}
	bl.${pc.componentName}.${fromField}.set = true
					</#if>
				</#list><#--list common.listRelationshipDetails(pc.componentImplementation, pc.relationshipImplementation) as details-->
			</#list><#-- protected.listProtectedParentComponents(c.componentName) as pc -->
		</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai -->

	return(0) | OK
}
<#-- SetInternalIdentifiers methods for non-root tables -->
		<#list protected.listNonRootTables(c.componentName) as table>

function extern long <@names.ST_DLLCode/>.${c.componentName}.${table.name}.SetInternalIdentifiers(
		long	i.internal.data)
{
DllUsage
	This function must only be used by the Tools Add-On package
	or the public layer.
	Do not use it in hook code or other libraries.
	Return value: 0 (OK) or an error value.
	Error values:
	  -1: multiple root table rows match the settings of the non-root row
	  -2: no root table row matches the settings of the non-root row
	DALHOOKERROR: a dal error message has been set.
EndDllUsage

	long	attributeNode	| child of instanceNode
	boolean	row.fetched	| indicates if a row has been fetched already
			<#assign locals=[]>
			<#list protected.getTableRelationIdentifiers(c, table.name) as identifier>
				<#list protected.listProtectedAttributes("", c.componentName) as iai>
					<#if identifier.attribute==iai.attributeName>
						<#if !protected.containedIn("local."+iai.componentName+"."+iai.attributeName, locals)>
							<#assign domain = common.getDatatypeName(common.getDatatypeFromAttributeImplementation(iai.attributeImplementation))>
							<#assign locals=locals+["local."+iai.componentName+"."+iai.attributeName]>
	domain	${domain}	local.${iai.componentName}.${iai.attributeName}
					</#if><#--if !protected.containedIn("local."+iai.componentName+"."+iai.attributeName, locals)-->
					</#if><#--if identifier.attribute==iai.attributeName-->
				</#list><#--list protected.listProtectedAttributes("", c.componentName) as iai -->
			</#list><#--list protected.getTableRelationIdentifiers(c, table.name) as identifier> -->
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
				<#list protected.listProtectedParentComponents(c.componentName) as pc>
					<#list common.listRelationshipDetails(pc.componentImplementation, pc.relationshipImplementation) as details>
						<#assign toField=details.toAttributeImplementation.name>
						<#if toField == iai.attributeName>
							<#if !protected.containedIn("local."+iai.componentName+"."+iai.attributeName, locals)>
								<#assign domain = common.getDatatypeName(common.getDatatypeFromAttributeImplementation(iai.attributeImplementation))>
	domain	${domain}	local.${iai.componentName}.${iai.attributeName}
							</#if>
						</#if>
					</#list><#--list common.listRelationshipDetails(pc.componentImplementation, pc.relationshipImplementation) as details-->
				</#list><#-- protected.listProtectedParentComponents(c.componentName) as pc -->
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai -->

	| get values
			<#assign attributeNodeUsed=false/>
			<#list protected.getTableRelationIdentifiers(c, table.name) as identifier>
				<#list protected.listProtectedAttributes("", c.componentName) as iai>
					<#if identifier.attribute==iai.attributeName>
						<#assign attributeNodeUsed=true/>
	attributeNode = xmlFindFirst("${identifier.column}", i.internal.data)
	ERR_IF(attributeNode = 0, "${c.componentName}")
	local.${iai.componentName}.${iai.attributeName} = 
						<#assign backendDatatype = common.get_BaanDatatype_from_XMLSchemaDatatype(common.getDatatype(iai.attributeImplementation))>
						<#switch backendDatatype>
		 				<#case "DB.LONG">
  						<#case "DB.DATE">
 		 				<#case "DB.TIME">
			lval(xmlData$(attributeNode))
							<#break>
		  				<#case "DB.DOUBLE">
			val(xmlData$(attributeNode))
							<#break>
						<#case "DB.ENUM">
			ltoe(lval(xmlData$(attributeNode)))
							<#break>
						<#default>
			xmlData$(attributeNode)
							<#break>
						</#switch><#-- switch datatype -->
					</#if><#--if identifier.attribute==iai.attributeName-->
				</#list><#--list protected.listProtectedAttributes("", c.componentName) as iai -->
			</#list><#--list protected.getTableRelationIdentifiers(c, table.name) as identifier> -->
			<#if !attributeNodeUsed>
	attributeNode = 0
			</#if><#--if !attributeNodeUsed-->

	| perform joining query to get top-level identifiers
	row.fetched = false
<#if names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0">
	#pragma language sql start 6
</#if><#--if names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0"-->
	select	*
	from	${rootTableName}
			<#-- Add rootTableName and the tables that are going to be joined to the printedFromTablesList,
				in order to avoid having them included in the From-part of the query -->
			<#assign printedFromTables=[rootTableName]/>
			<#list protected.listOfComponentTables(c, false, table.name) as theTable>
				<#assign parentTablesWithColumns=protected.getParentTablesWithColumns(c, theTable)/>
				<#assign theFirst=true/>
				<#list parentTablesWithColumns as column>
					<#if theFirst>
						<#if protected.containedIn(theTable, printedFromTables)>
							<#assign printedFromTables=printedFromTables+[column.parentTable.name]/>
						<#else>
							<#assign printedFromTables=printedFromTables+[theTable]/>
						</#if><#--if protected.containedIn(theTable, printedFromTables)-->
						<#assign theFirst=false/>
					</#if><#--if theFirst-->
				</#list><#--list parentTableWithColumns.columns as column-->
			</#list><#--list protected.listOfComponentTables(c, false) as theTable-->
			<#list protected.listOfComponentTables(c, false, table.name) as theTable>
				<#if theTable!=rootTableName>
					<#list protected.getParentTablesWithColumns(c, theTable) as column>
						<#assign parentTable=column.parentTable.name>
						<#if parentTable!="" && !protected.containedIn(parentTable,printedFromTables)>
		, ${parentTable}
							<#assign printedFromTables=printedFromTables+[parentTable]/>
						</#if><#--if parentTable!="" && !protected.containedIn(parentTable,printedFromTables)-->
					</#list><#--list protected.getParentTablesWithColumns(c, theTable) as column-->
				</#if><#--if theTable!=rootTableName-->
			</#list><#--list protected.listOfComponentTables(c, false) as theTable-->
			<#assign printedFromTables=[rootTableName]/>
			<#list protected.listOfComponentTables(c, false, table.name) as theTable>
				<#assign parentTablesWithColumns=protected.getParentTablesWithColumns(c, theTable)/>
				<#assign theFirst=true/>
				<#list parentTablesWithColumns as column>
					<#if protected.containedIn(theTable, printedFromTables)>
						<#if protected.containedIn(column.parentTable.name, printedFromTables)>
				and ${column.parentTable.name}.${column.name}=${theTable}.${column.toName}
						<#else>
		left outer join ${column.parentTable.name} on ${column.parentTable.name}.${column.name}=${theTable}.${column.toName}
							<#assign printedFromTables=printedFromTables+[column.parentTable.name]/>
						</#if><#--if protected.containedIn(column.parentTable.name, printedFromTables)-->
					<#else>
		left outer join ${theTable} on ${column.parentTable.name}.${column.name}=${theTable}.${column.toName}
							<#assign printedFromTables=printedFromTables+[theTable]/>
					</#if><#--if protected.containedIn(theTable, printedFromTables)-->
				</#list><#--list parentTablesWithColumns.columns as column-->
			</#list><#--list protected.listOfComponentTables(c, false) as theTable-->
			<#assign theFirst=true/>
			<#list protected.getTableRelationIdentifiers(c, table.name) as identifier>
				<#if theFirst>
	where	${identifier.table}.${identifier.column} = :local.${c.componentName}.${identifier.attribute}
					<#assign theFirst=false/>
				<#else>
		and ${identifier.table}.${identifier.column} = :local.${c.componentName}.${identifier.attribute}
				</#if><#--if theFirst-->
			</#list><#--list protected.getTableRelationIdentifiers(c, table.name) as identifiers-->
	as set with 2 rows
	selectdo
		if not row.fetched then
			row.fetched = true
			| set identifiers for current component
			<#list protected.listInternalIdentifiers(c.componentName, true) as iai>
			bl.${iai.componentName}.${iai.attributeName} = ${iai.attributeImplementation.componentImplementationTable.idref.table.idref.name}.${iai.attributeImplementation.column.idref.name}
			bl.${iai.componentName}.${iai.attributeName}.set = true
			</#list><#-- protected.listInternalIdentifiers(c.componentName, true) as iai -->

			| Set identifiers for parent components
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
				<#list protected.listProtectedParentComponents(c.componentName) as pc>
					<#list common.listRelationshipDetails(pc.componentImplementation, pc.relationshipImplementation) as details>
						<#assign toField=details.toAttributeImplementation.name>
						<#assign fromField=details.fromAttributeImplementation.name>
						<#if toField == iai.attributeName>
			bl.${pc.componentName}.${fromField} = local.${iai.componentName}.${iai.attributeName}
			bl.${pc.componentName}.${fromField}.set = true
						</#if>
					</#list><#--list common.listRelationshipDetails(pc.componentImplementation, pc.relationshipImplementation) as details-->
				</#list><#-- protected.listProtectedParentComponents(c.componentName) as pc -->
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai -->
		else
			return(-1) | multiple matching rows
		endif
	selectempty
		return(-2) | no matching rows
	endselect
<#if names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0">
	#pragma language sql end 6
</#if><#--if names.applicationBackendRelease == "BaanIV" || names.applicationBackendRelease == "BaanERP5.0"-->

	return(0) | OK
}

		</#list><#--list protected.listNonRootTables(c.componentName) as table-->
<#-- GetRootTableIdentifiers method, to be used for Publisher
Format:
	<Data>
		<columnValue column="...">...</columnValue>
		...
	</Data>
-->
function extern long <@names.ST_DLLCode/>.${c.componentName}.GetRootTableIdentifiers(
	ref	long	o.internalData)
{
DllUsage
	This function must only be used by the Publisher DLL (included in the
	Tools Add-On package).
	Do not use it in hook code or other libraries.
	Return value: 0 (OK) or an error value.
	In case of error a dal error message has been set.
EndDllUsage

	long	attributeNode	| node containing attribute
	long	retl		| return value to be checked

	o.internalData = xmlNewNode("Data")

		<#assign variablesUsed=false/>
		<#list protected.listRootTableIdentifiers(c.componentName) as rti>
			<#assign variablesUsed=true/>
	| add ${rti.attributeImplementation.column.idref.name} / bl.${rti.componentName}.${rti.attributeName}
	ERR_IF(not bl.${rti.componentName}.${rti.attributeName}.set)
	attributeNode = xmlNewDataElement("columnValue",
					bl.${rti.componentName}.${rti.attributeName},
					o.internalData)
	ERR_IF(attributeNode = 0)
	retl = xmlSetAttribute(attributeNode, "column", "${rti.attributeImplementation.column.idref.name}")
	ERR_IF(retl = 0)

		</#list><#-- protected.listRootTableIdentifiers(c.componentName) as iai -->
		<#if !variablesUsed>
	attributeNode = 0
	retl = 0
	
		</#if>
	return(0) | OK
}

	</#list><#-- protected.listProtectedComponents() as c -->
</#if><#-- common.methodPresent("PublishEvent") -->
<#if common.methodPresent("PublishEvent")>
	<#list protected.listProtectedComponents() as c>
		<#if object.businessInterfaceDefinition.idref.type!="bod" || 
			(object.businessInterfaceDefinition.idref.type=="bod" &&
			 c.componentName==names.businessInterfaceName)>
|------------ GetInternalIdentifiersXml() for ${c.componentName} ------------

function boolean <@names.ST_DLLCode/>.${c.componentName}.GetInternalIdentifiersXml(
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
				<#assign domain = common.getDatatypeName(common.getDatatypeFromAttributeImplementation(iai.attributeImplementation))>
     	domain  ${domain}  i.${iai.attributeName}, 
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
	ref	long	o.identifiersXml)
{
| Create XML containing input for <@names.ST_DLLCode/>.${c.componentName}.SetInternalIdentifiers()
| Return value: true = OK, false = error

	long	attributeNode	| xml node for attribute element
	long	duml			| dummy variable

	o.identifiersXml = xmlNewNode("${c.componentName}")
	if o.identifiersXml = 0 then
		return(false)
	endif
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
	attributeNode = xmlNewDataElement("${iai.attributeName}", i.${iai.attributeName}, o.identifiersXml)
   	<#--#TODO need data type conversion?-->
	if attributeNode = 0 then
		duml = xmlDelete(o.identifiersXml)
		o.identifiersXml = 0
		return(false)
	endif
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
	return(true)
}
		</#if><#--if object.businessInterfaceDefinition.idref.type!="bod" || 
			        (object.businessInterfaceDefinition.idref.type=="bod" &&
			         c.componentName==names.businessInterfaceName)-->
		<#if object.businessInterfaceDefinition.idref.type!="bod">

|------------ ShowAndPublishEvent() for ${c.componentName} ------------

<#-- Define used in ShowAndPublishEvent and ShowAndPublishStandardEvent. -->
<#-- We should never return an error, but publish an error message instead! -->
#define PUBLISH_ERROR_IF(condition, action)
^	if condition then
^		dal.set.error.message("tlbctst0010",
^			"${names.businessInterfaceName}", "${c.componentName}")
^		|* Unable to execute ShowAndPublishEvent for %1$s.%2$s).
^		tlbct.dll1000.PublishDalErrorMessagesIfSubscription(
^			"${names.businessInterfaceName}",
^			 isspace(action) ? "actionUnknown" : action)
^		return(0) | always return OK value
^	endif

function extern long <@names.ST_DLLCode/>.${c.componentName}.ShowAndPublishEvent(
	const	string		i.eventAction,
	<#-- Generate input argument for each identifier of table -->
			<#assign argcount = 1>
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
				<#assign argcount = argcount + 1>
				<#assign domain = common.getDatatypeName(common.getDatatypeFromAttributeImplementation(iai.attributeImplementation))>
     	domain  ${domain}  i.${iai.attributeName}, 
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
 		[boolean	i.instanceAvailable,
	const	string		i.actionType])
{
DllUsage
Desc	This function publishes an event for the instance defined by the input parameters.
	If a subscription exists for the BDE then
	- the values for the public identifying attributes are determined
	- the Show request is built and the Show is invoked (unless i.identifierOnly)
	- an event message is created (using the Show response if applicable)
	- the event message is published through PublishEvent().
	- in case of errors, an error message is published.
	If no subscription exists then nothing is done (not even an error message).
Input	i.eventAction	event action (must be filled)
	other parameters	identifiers for the component's root table
	i.instanceAvailable	optional, true if unspecified;
			if false, only identifiers are included
			in the event message and the Show method is unused;
			this must only be set to false if the instance is
			unavailable so the Show would fail!
	i.actionType	action type of the current component
Output	return value	0 (OK)
EndDllUsage

	long	identifiersXml	| xml containing identifying attributes and their values
	long	retl		| return value to be checked
	long	duml		| dummy variable

	CHECK_TOOLS_VERSION_SHOW_AND_PUB(0)

	if get.argc() > ${argcount} then
		i.instanceAvailable = get.boolean.arg(${argcount+1})
	else
		i.instanceAvailable = true
	endif
	if false then
		| prevent compile warning on unused variable
		duml = lval(i.actionType)
	endif

	<#--SetInternalIdentifiers is used here to establish that the values
	    are set when the Show method is called -->
	retl = <@names.ST_DLLCode/>.${c.componentName}.SetInternalIdentifiers(
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
    			i.${iai.attributeName},
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
			duml)
	PUBLISH_ERROR_IF(retl <> 0, i.eventAction)

	<#--build xml to be used as input for set internal identifiers (by publisher)-->
	PUBLISH_ERROR_IF(not <@names.ST_DLLCode/>.${c.componentName}.GetInternalIdentifiersXml(
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
    			i.${iai.attributeName},
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
			identifiersXml),
			i.eventAction)

	on case get.argc()
	case ${argcount}:
	case ${argcount+1}:
		retl = tlbct.dll1000.DefaultOnExecute.ShowAndPublishEvent(
				"${names.businessInterfaceName}",
				"${c.componentName}",
				i.eventAction,
				i.instanceAvailable,
				"", 	| action type
				identifiersXml)
		break
	case ${argcount+2}:
		retl = tlbct.dll1000.DefaultOnExecute.ShowAndPublishEvent(
				"${names.businessInterfaceName}",
				"${c.componentName}",
				i.eventAction,
				i.instanceAvailable,
				get.string.arg(${argcount+2}),	| action type
				identifiersXml)
		break
	endcase
	duml = xmlDelete(identifiersXml)
	identifiersXml = 0
	PUBLISH_ERROR_IF(retl <> 0, i.eventAction)

	return(0) | OK
}

function extern long <@names.ST_DLLCode/>.${c.componentName}.ShowAndPublishStandardEvent(
    const       string          i.actionType
	<#-- Generate input argument for each identifier of table -->
			<#assign argcount = 1>
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
				<#assign argcount = argcount + 1>
				<#assign domain = common.getDatatypeName(common.getDatatypeFromAttributeImplementation(iai.attributeImplementation))>
     	, domain  ${domain}  i.${iai.attributeName}
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
				)
{
DllUsage
Desc	This function is comparable to ShowAndPublishEvent(), except that
	the event action is not specified, but the action type at
	component level is specified instead.
	Additionally, which component instances are published depends on the
	action type. For example, for a change action, only the changed
	component and its unchanged parents (if any) are published.
Input	i.actionType	action to be published for the component instance;
			must have one of the following values: "create", "change" or "delete".
			Important: in case of an insert or delete for a NON-ROOT table of
			the component, the action type must be "change".
	other parameters	identifiers for the component's root table
Output	return value	0 (OK)
EndDllUsage

	long	identifiersXml	| xml containing identifying attributes and their values
	long	retl			| return value to be checked
	long	duml			| dummy variable

	CHECK_TOOLS_VERSION_SHOW_AND_PUB(0)

	<#--In theory SetInternalIdentifiers is not needed anymore here, but it is still
	    included for compatibility with FP2 -->
	retl = <@names.ST_DLLCode/>.${c.componentName}.SetInternalIdentifiers(
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
    			i.${iai.attributeName},
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
				duml)
	PUBLISH_ERROR_IF(retl <> 0, i.actionType)

	<#--build xml to be used as input for set internal identifiers (by publisher)-->
	PUBLISH_ERROR_IF(not <@names.ST_DLLCode/>.${c.componentName}.GetInternalIdentifiersXml(
			<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
    				i.${iai.attributeName},
			</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
					identifiersXml),
			i.actionType)

	retl = tlbct.dll1000.DefaultOnExecute.ShowAndPublishEvent(
			"${names.businessInterfaceName}",
			"${c.componentName}",
			<#if c.componentName == names.businessInterfaceName>
			tolower$(strip$(i.actionType)), | event action is same as action type
			tolower$(strip$(i.actionType)) <> "delete", | instance available
			<#else>
			"change",	| event action
			true,		| object instance is available
			</#if>
			i.actionType,
			identifiersXml)
	duml = xmlDelete(identifiersXml)
	identifiersXml = 0
	PUBLISH_ERROR_IF(retl <> 0, i.actionType)

	return(0) | OK
}

#undef PUBLISH_ERROR_IF(condition, action)

		</#if><#--if object.businessInterfaceDefinition.idref.type!="bod"-->
		<#if c.componentName==names.businessInterfaceName>
			<#if object.businessInterfaceDefinition.idref.type=="bod">
<#--BOD Type: generate SAPE methods for every verb-->
<#-- Define used in ShowAndPublish<Verb>BOD. -->
#define DALHOOKERROR_IF(condition, action)
^	if condition then
^		dal.set.error.message("tlbctst0014",
^			action, "${names.businessInterfaceName}", "${c.componentName}")
^		| Unable to execute ShowAndPublish%1$sBOD for %2$s.%3$s.
^		return(DALHOOKERROR) 
^	endif

				<#list ["Sync", "Process", "Load", "Post", "Update", "Show"] as verb>
<#--#Note: the "Get" verb does not have a ShowAndPublish<Verb>BOD method.-->
					<#if common.eventCanBePublished(verb)>
|------------ ShowAndPublish${verb}BOD() for ${c.componentName} ------------

function extern long <@names.ST_DLLCode/>.${c.componentName}.ShowAndPublish${verb}BOD(
	<#-- Generate input argument for each identifier of table -->
						<#assign nrParameters = 7><#-- for the fixed parameters -->
						<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
							<#assign domain = common.getDatatypeName(common.getDatatypeFromAttributeImplementation(iai.attributeImplementation))>
							<#assign nrParameters = nrParameters + 1>
     	domain  ${domain}		i.${iai.attributeName}, 
						</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
	const	string		i.actionCode,
	const	string		i.documentId,
	const	string		i.revisionId,
	const	string		i.variationId,
	const	string		i.tenantId,
	const	string		i.accountingEntityId,
	const	string		i.locationId,
	[	long		i.settings ] )
{
DllUsage
Desc	This function publishes an event for the instance defined by the input parameters.
	- the values for the public identifying attributes are determined
	- the Show request is built and the Show is invoked (unless i.actionCode =
	  "Delete" and the component is the top-level component)
	- the metadata is retrieved
	- an event message is created (using the Show response if applicable)
	- the event message is published through PublishBOD().
	- in case of errors, DALHOOKERROR is returned
Input	other parameters identifiers for the components root table
	i.actionCode          action code
	i.documentId          document ID
	i.revisionId          revision ID
	i.variationId         variation ID
	i.tenantId            tenant ID
	i.accountingEntityId  accounting entity ID
	i.locationId          location ID
	i.settings		XML containing additional settings (optional);
				refer to the developer's documentation for more information
Output	return value	0 (OK) or DALHOOKERROR (Error)
EndDllUsage

	long	identifiersXml	| xml containing identifying attributes and their values
	long	metadataXml	| xml containing metadata
	long	o.result	| result from tlbct.dll1000.CreateMetaDataNode
	long	retl		| return value to be checked
	long	duml		| dummy variable

	CHECK_TOOLS_VERSION_SHOW_AND_PUB(0)

	<#--SetInternalIdentifiers is used here to establish that the values
	    are set when the Show method is called -->
	retl = <@names.ST_DLLCode/>.${c.componentName}.SetInternalIdentifiers(
						<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
    			i.${iai.attributeName},
						</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
			duml)
	DALHOOKERROR_IF(retl <> 0, "${verb}")

	<#--build xml to be used as input for set internal identifiers (by publisher)-->
	DALHOOKERROR_IF(not <@names.ST_DLLCode/>.${c.componentName}.GetInternalIdentifiersXml(
						<#list protected.listInternalIdentifiers(c.componentName, false) as iai>
			i.${iai.attributeName},
						</#list><#-- protected.listInternalIdentifiers(c.componentName, false) as iai-->
			identifiersXml),
			"${verb}")

	<#--build xml to be used as input for metadata (by publisher)-->
	retl = tlbct.dll1000.CreateMetaDataNode(
				"<@names.SB_Object/>", "<@names.SB_DLLCode/>.",
				"<@names.ST_Object/>", "<@names.ST_DLLCode/>.",
				metadataXml,
				o.result,
				"bod")
	if o.result <> 0 then
		duml = xmlDelete(o.result) | not used
		o.result = 0	
	endif
	DALHOOKERROR_IF(retl <> 0, "${verb}")

	if get.argc() > ${nrParameters} then
		i.settings = get.long.arg(${nrParameters} + 1)
	else
		i.settings = 0
	endif
	retl = tlbct.dll1000.DefaultOnExecute.ShowAndPublishBOD(
			"${names.businessInterfaceName}",
			"${names.noun}",
			"${verb}",	| event action
			identifiersXml,
			metadataXml,
			i.actionCode,
			i.documentId,
			i.revisionId,
			i.variationId,
			i.tenantId,
			i.accountingEntityId,
			i.locationId,
			i.settings)
			
	duml = xmlDelete(identifiersXml)
	identifiersXml = 0

	duml = xmlDelete(metadataXml)
	metadataXml = 0

	DALHOOKERROR_IF(retl <> 0, "${verb}") | error from ShowAndPublishBOD

	return(0) | OK
}

					</#if><#--if eventCanBePublished(verb)-->
				</#list><#--list ["Sync", "Process", "Load", "Post", "Update"] as verb-->
#undef DALHOOKERROR_IF(condition, action)
			</#if><#-- if object.businessInterfaceDefinition.idref.type="bod" -->
		</#if><#-- if c.componentName == names.businessInterfaceName -->
	</#list><#-- list protected.listProtectedComponents() as c -->
</#if><#-- if common.methodPresent("PublishEvent") -->
<#if object.businessInterfaceDefinition.idref.type="bod">

|------------------- Check whether publishing is on ---------------------------

function extern boolean <@names.ST_DLLCode/>.${names.businessInterfaceName}.EventMustBePublished(
	const	string		i.verb)
{
DllUsage
Desc    This function checks whether a 'subscription' exists for the specified
        noun and verb (in the current company).
Input   i.verb          : the BOD verb
Output  return value    : true if the BOD must be published (a 'subscription'
                          exists); false otherwise.
EndDllUsage

	CHECK_TOOLS_VERSION_SHOW_AND_PUB(false)

	return(tlbct.dll1000.bod.must.be.published("${names.noun}", i.verb))
}
</#if><#--if object.businessInterfaceDefinition.idref.type="bod"-->