Inhalte

Alarm Message Service: Factories

Table of Contents

Introduction

All required collection interfaces are defined now. So let’s define the belonging factories.

Preparation

Since we already need the factories for the collections, we can first create empty classes for the concrete implementation so that we can start with the factories.

For the empty classes, the pragmas {attribute 'enable_dynamic_creation'} and {attribute 'reflection'} are required

So first create the following empty classes:

FUNCTION_BLOCK DoublyLinkedElement EXTENDS Object IMPLEMENTS IDoublyLinkedElement
FUNCTION_BLOCK SingleThreadObjectList EXTENDS Object IMPLEMENTS IList
FUNCTION_BLOCK SynchronizedObjectList EXTENDS Object IMPLEMENTS IList
FUNCTION_BLOCK AlarmMessageQueue EXTENDS Object IMPLEMENTS IAlarmMessageQueue
FUNCTION_BLOCK AlarmMessageServiceSubscriberList EXTENDS Object IMPLEMENTS IAlarmMessageServiceSubscriberList

For the class DoublyLinkedElement is a FB_init method with the following inputs required:

content 	:IObject;
next 		:IDoublyLinkedElement;
previous 	:IDoublyLinkedElement;

Interfaces

Interface IDoublyLinkedElementFactory
INTERFACE IDoublyLinkedElementFactory EXTENDS IObject
METHOD destructDoublyLinkedElement
VAR_INPUT
	element 		:IDoublyLinkedElement;
	unlinkElement 	:BOOL;
END_VAR
METHOD getNewDoublyLinkedElement :IDoublyLinkedElement
VAR_INPUT
	object 				:IObject;
	previousElement 	:IDoublyLinkedElement;
	nextElement 		:IDoublyLinkedElement;
	linkElements 		:BOOL;
END_VAR
Interface IObjectListFactory
INTERFACE IObjectListFactory EXTENDS IObject
METHOD destructObjectList
VAR_INPUT
	objectList :IList;
END_VAR
METHOD getNewObjectList :IList
Interface ISynchronizedObjectListFactory
INTERFACE ISynchronizedObjectListFactory EXTENDS IObject
METHOD getNewSynchronizedObjectList :IList
METHOD destructSynchronizedObjectList
VAR_INPUT
	synchronizedObjectList :IList;
END_VAR
Interface IAlarmMessageQueueFactory
INTERFACE IAlarmMessageQueueFactory EXTENDS IObject
METHOD getNewAlarmMessageQueue :IAlarmMessageQueue
METHOD destructAlarmMessageQueue
VAR_INPUT
	alarmMessageQueue :IAlarmMessageQueue;
END_VAR
Interface IAlarmMessageServiceSubscriberListFactory
INTERFACE IAlarmMessageServiceSubscriberListFactory EXTENDS IObject
METHOD getNewAlarmMessageServiceSubscriberList :IAlarmMessageServiceSubscriberList
METHOD destructAlarmMessageServiceSubscriberList
VAR_INPUT
	alarmMessageServiceSubscriberList	:IAlarmMessageServiceSubscriberList;
END_VAR
Interface ICollectionFactory
INTERFACE ICollectionFactory EXTENDS
	IObject, 
	IObjectListFactory, 
	ISynchronizedObjectListFactory, 
	IAlarmMessageQueueFactory, 
	IAlarmMessageServiceSubscriberListFactory, 
	IDoublyLinkedElementFactory
Interface ICollectionFactoryProvider
INTERFACE ICollectionFactoryProvider EXTENDS IObject
METHOD getAlarmMessageQueueFactory :IAlarmMessageQueueFactory
METHOD getDoublyLinkedElementFactory :IDoublyLinkedElementFactory
METHOD getObjectListFactory :IObjectListFactory
METHOD getAlarmMessageServiceSubscriberListFactory :IAlarmMessageServiceSubscriberListFactory
METHOD getSynchronizedObjectListFactory :ISynchronizedObjectListFactory

Implementation

It is required to implement a class with default factory methods, the factory provider must always return a valid factory.

Class CollectionFactory
FUNCTION_BLOCK CollectionFactory EXTENDS Object IMPLEMENTS ICollectionFactory
GET PROPERTY className :ClassName


className := 'CollectionFactory';
METHOD destructAlarmMessageQueue
VAR_INPUT
	alarmMessageQueue	:IAlarmMessageQueue;
END_VAR
VAR
	concreteList :POINTER TO AlarmMessageQueue;
END_VAR
IF (THIS^.isObjectNull(alarmMessageQueue)) THEN
	RETURN;
END_IF

IF (__QUERYPOINTER(alarmMessageQueue, concreteList)) THEN
	__DELETE(concreteList);
END_IF
METHOD destructAlarmMessageServiceSubscriberList
VAR_INPUT
	alarmMessageServiceSubscriberList	:IAlarmMessageServiceSubscriberList;
END_VAR
VAR
	concreteList :POINTER TO AlarmMessageServiceSubscriberList;
END_VAR
RETURN(THIS^.isObjectNull(alarmMessageServiceSubscriberList));

IF (__QUERYPOINTER(alarmMessageServiceSubscriberList, concreteList)) THEN
	__DELETE(concreteList);
END_IF
METHOD destructDoublyLinkedElement
VAR_INPUT
	element :IDoublyLinkedElement;
	unlinkElement :BOOL;
END_VAR
VAR
	concreteElement :POINTER TO DoublyLinkedElement;
END_VAR
RETURN(THIS^.isObjectNull(element));

IF (__QUERYPOINTER(element, concreteElement)) THEN
	IF (unlinkElement) THEN
		IF (THIS^.isObjectValid(element.previous)) THEN
			element.previous.next := element.next;
		END_IF
		
		IF (THIS^.isObjectValid(element.next)) THEN
			element.next.previous := element.previous;
		END_IF
	END_IF
	__DELETE(concreteElement);
END_IF
METHOD destructObjectList
VAR_INPUT
	objectList :IList;
END_VAR
VAR
	concreteList :POINTER TO SingleThreadObjectList;
END_VAR
RETURN(THIS^.isObjectNull(objectList));

IF (__QUERYPOINTER(objectList, concreteList)) THEN
	__DELETE(concreteList);
END_IF
METHOD destructSynchronizedObjectList
VAR_INPUT
	synchronizedObjectList	:IList;
END_VAR
VAR
	concreteList :POINTER TO SynchronizedObjectList;
END_VAR
RETURN(THIS^.isObjectNull(synchronizedObjectList));

IF (__QUERYPOINTER(synchronizedObjectList, concreteList)) THEN
	__DELETE(concreteList);
END_IF
METHOD getNewAlarmMessageQueue :IAlarmMessageQueue
VAR
	newList :POINTER TO AlarmMessageQueue;
END_VAR
VAR CONSTANT
	NULL :__XWORD := 0;
END_VAR
newList := __NEW(AlarmMessageQueue());
getNewAlarmMessageQueue := NULL;
IF (newList <> NULL) THEN
	getNewAlarmMessageQueue := newList^;
END_IF
METHOD getNewAlarmMessageServiceSubscriberList :IAlarmMessageServiceSubscriberList
VAR
	newList :POINTER TO AlarmMessageServiceSubscriberList;
END_VAR
VAR CONSTANT
	NULL :__XWORD := 0;
END_VAR
newList := __NEW(SubscriberList());
getNewAlarmMessageServiceSubscriberList := NULL;
IF (newList <> NULL) THEN
	getNewAlarmMessageServiceSubscriberList := newList^;
END_IF
METHOD getNewDoublyLinkedElement :IDoublyLinkedElement
VAR_INPUT
	object				:IObject;
	previousElement		:IDoublyLinkedElement;
	nextElement			:IDoublyLinkedElement;
	linkElements		:BOOL;
END_VAR
VAR
	newElement 			:POINTER TO DoublyLinkedElement;
END_VAR
VAR CONSTANT
	NULL :__XWORD := 0;
END_VAR
getNewDoublyLinkedElement := NULL;
newElement := __NEW(
	DoublyLinkedElement(
		content := object,
		next := nextElement,
		previous := previousElement
	)
);

RETURN(newElement = NULL);

IF (THIS^.isObjectValid(newElement^)) THEN
	IF (linkElements) THEN
		IF (THIS^.isObjectValid(previousElement)) THEN
			previousElement.next := newElement^;
		END_IF
		
		IF (THIS^.isObjectValid(nextElement)) THEN
			nextElement.previous := newElement^;
		END_IF
	END_IF
END_IF

getNewDoublyLinkedElement := newElement^;
METHOD getNewObjectList :IList
VAR
	newList :POINTER TO SingleThreadObjectList;
END_VAR
VAR CONSTANT
	NULL :__XWORD := 0;
END_VAR
newList := __NEW(SingleThreadObjectList());
getNewObjectList := NULL;
IF (newList <> NULL) THEN
	getNewObjectList := newList^;
END_IF
METHOD getNewSynchronizedObjectList :IList
VAR
	newList :POINTER TO SynchronizedObjectList;
END_VAR
VAR CONSTANT
	NULL :__XWORD := 0;
END_VAR
newList := __NEW(SynchronizedObjectList());
getNewSynchronizedObjectList := NULL;
IF (newList <> NULL) THEN
	getNewSynchronizedObjectList := newList^;
END_IF
Class FactoryProvider

FUNCTION_BLOCK FactoryProvider EXTENDS Object IMPLEMENTS ICollectionFactoryProvider
VAR_STAT
	{attribute 'hide'}
	defaultFactories				:CollectionFactory();
	{attribute 'hide'}
	doublyLinkedElementFactory		:IDoublyLinkedElementFactory;
	{attribute 'hide'}
	listFactory						:IObjectListFactory;
	{attribute 'hide'}
	syncListFactory					:ISynchronizedObjectListFactory;
	{attribute 'hide'}
	subscriberListFactory			:IAlarmMessageServiceSubscriberListFactory;
	{attribute 'hide'}
	alarmMessageQueueFactory		:IAlarmMessageQueueFactory;
	{attribute 'hide'}
	lockObjectDoublyLinkedElement	:TC2_System.FB_IecCriticalSection;
	{attribute 'hide'}
	lockObjectList					:TC2_System.FB_IecCriticalSection;
	{attribute 'hide'}
	lockObjectSyncList				:TC2_System.FB_IecCriticalSection;
	{attribute 'hide'}
	lockObjectSubscriberList		:TC2_System.FB_IecCriticalSection;
	{attribute 'hide'}
	lockObjectAlarmMessageQueue		:TC2_System.FB_IecCriticalSection;	
END_VAR
METHOD PRIVATE isObjectStatic :BOOL;
VAR_INPUT
	object	:IObject;
END_VAR
VAR
	address	:POINTER TO __XWORD;
END_VAR
address := ADR(object);
isObjectStatic := (
	Tc2_System.F_CheckMemoryArea(
		pData := address^,
		nSize := SIZEOF(__XWORD)
	) = Tc2_System.E_TcMemoryArea.Static
);
METHOD PRIVATE setAlarmMessageQueueFactory
VAR_INPUT
	(* must be in static memory area declared and can be set once only *)
	alarmMessageQueueFactory	:IAlarmMessageQueueFactory;		
END_VAR
THIS^.lockObjectAlarmMessageQueue.Enter();
IF (
	THIS^.isObjectStatic(alarmMessageQueueFactory) 
	AND_THEN (
		THIS^.isObjectNull(THIS^.alarmMessageQueueFactory)
		OR_ELSE THIS^.defaultFactories.isEqual(THIS^.alarmMessageQueueFactory)
	)
) THEN
	THIS^.alarmMessageQueueFactory := alarmMessageQueueFactory;
END_IF
THIS^.lockObjectAlarmMessageQueue.Leave();
METHOD PRIVATE setDoublyLinkedElementFactory
VAR_INPUT
	(* must be in static memory area declared and can be set once only *)
	doublyLinkedElementFactory	:IDoublyLinkedElementFactory;
END_VAR
THIS^.lockObjectDoublyLinkedElement.Enter();
IF (
	THIS^.isObjectStatic(doublyLinkedElementFactory) 
	AND_THEN (
		THIS^.isObjectNull(THIS^.doublyLinkedElementFactory)
		OR_ELSE THIS^.defaultFactories.isEqual(THIS^.doublyLinkedElementFactory)
	)
) THEN
	THIS^.doublyLinkedElementFactory := doublyLinkedElementFactory;
END_IF
THIS^.lockObjectDoublyLinkedElement.Leave();
METHOD PRIVATE setAlarmMessageServiceSubscriberListFactory
VAR_INPUT
	(* must be in static memory area declared and can be set once only *)
	subscriberListFactory	:IAlarmMessageServiceSubscriberListFactory;
END_VAR
THIS^.lockObjectSubscriberList.Enter();
IF (
	THIS^.isObjectStatic(subscriberListFactory) 
	AND_THEN (
		THIS^.isObjectNull(THIS^.subscriberListFactory)
		OR_ELSE THIS^.defaultFactories.isEqual(THIS^.subscriberListFactory)
	)
) THEN
	THIS^.subscriberListFactory := subscriberListFactory;
END_IF
THIS^.lockObjectSubscriberList.Leave();
METHOD PRIVATE setListFactory
VAR_INPUT
	(* must be in static memory area declared and can be set once only *)
	listFactory	:IObjectListFactory;
END_VAR
THIS^.lockObjectList.Enter();
IF (
	THIS^.isObjectStatic(listFactory) 
	AND_THEN (
		THIS^.isObjectNull(THIS^.listFactory)
		OR_ELSE THIS^.defaultFactories.isEqual(THIS^.listFactory)
	)
) THEN
	THIS^.listFactory := listFactory;
END_IF
THIS^.lockObjectList.Leave();
METHOD PRIVATE setSyncListFactory
VAR_INPUT
	(* must be in static memory area declared and can be set once only *)
	syncListFactory	:ISynchronizedObjectListFactory;
END_VAR
THIS^.lockObjectSyncList.Enter();
IF (
	THIS^.isObjectStatic(syncListFactory) 
	AND_THEN (
		THIS^.isObjectNull(THIS^.syncListFactory)
		OR_ELSE THIS^.defaultFactories.isEqual(THIS^.syncListFactory)
	)
) THEN
	THIS^.syncListFactory := syncListFactory;
END_IF
THIS^.lockObjectSyncList.Leave();
METHOD FB_init :BOOL
VAR_INPUT
	(* if TRUE, the retain variables are initialized (warm start / cold start) *)
	bInitRetains :BOOL;
	(* if TRUE, the instance afterwards gets moved into the copy code (online change) *)
	bInCopyCode :BOOL;
	(* must be in static memory area declared and can be set once only *)
	doublyLinkedElementFactory	:IDoublyLinkedElementFactory;
	(* must be in static memory area declared and can be set once only *)
	listFactory					:IObjectListFactory;
	(* must be in static memory area declared and can be set once only *)
	syncListFactory				:ISynchronizedObjectListFactory;
	(* must be in static memory area declared and can be set once only *)
	subscriberListFactory		:IAlarmMessageServiceSubscriberListFactory;
	(* must be in static memory area declared and can be set once only *)
	alarmMessageQueueFactory	:IAlarmMessageQueueFactory;		
END_VAR
VAR
	{attribute 'hide'}
	newHashstate3 :Hashcode;
END_VAR
VAR CONSTANT
	{attribute 'hide'}
	NUMBER_OF_LEFT_SHIFTS :UINT := 17;
	{attribute 'hide'}
	NUMBER_OF_LEFT_ROTATIONS :UINT := 45;
	NULL :__XWORD := 0;
END_VAR
THIS^.setDoublyLinkedElementFactory(doublyLinkedElementFactory);
THIS^.setListFactory(listFactory);
THIS^.setSyncListFactory(syncListFactory);
THIS^.setAlarmMessageServiceSubscriberListFactory(subscriberListFactory);
THIS^.setAlarmMessageQueueFactory(alarmMessageQueueFactory);
GET PROPERTY className :ClassName


className := 'FactoryProvider';
METHOD getAlarmMessageQueueFactory :IAlarmMessageQueueFactory
THIS^.lockObjectAlarmMessageQueue.Enter();
IF (THIS^.isObjectValid(THIS^.alarmMessageQueueFactory)) THEN
	getAlarmMessageQueueFactory := THIS^.alarmMessageQueueFactory;
ELSE
	getAlarmMessageQueueFactory := THIS^.defaultFactories;
END_IF
THIS^.lockObjectAlarmMessageQueue.Leave();
METHOD getAlarmMessageServiceSubscriberListFactory :IAlarmMessageServiceSubscriberListFactory
THIS^.lockObjectSubscriberList.Enter();
IF (THIS^.isObjectValid(THIS^.subscriberListFactory)) THEN
	getAlarmMessageServiceSubscriberListFactory := THIS^.subscriberListFactory;
ELSE
	getAlarmMessageServiceSubscriberListFactory := THIS^.defaultFactories;
END_IF
THIS^.lockObjectSubscriberList.Leave();
METHOD getDoublyLinkedElementFactory :IDoublyLinkedElementFactory
THIS^.lockObjectDoublyLinkedElement.Enter();
IF (THIS^.isObjectValid(THIS^.doublyLinkedElementFactory)) THEN
	getDoublyLinkedElementFactory := THIS^.doublyLinkedElementFactory;
ELSE
	getDoublyLinkedElementFactory := THIS^.defaultFactories;
END_IF
THIS^.lockObjectDoublyLinkedElement.Leave();
METHOD getObjectListFactory :IObjectListFactory
THIS^.lockObjectList.Enter();
IF (THIS^.isObjectValid(THIS^.listFactory)) THEN
	getObjectListFactory := THIS^.listFactory;
ELSE
	getObjectListFactory := THIS^.defaultFactories;
END_IF
THIS^.lockObjectList.Leave();
METHOD getSynchronizedObjectListFactory :ISynchronizedObjectListFactory
THIS^.lockObjectSyncList.Enter();
IF (THIS^.isObjectValid(THIS^.syncListFactory)) THEN
	getSynchronizedObjectListFactory := THIS^.syncListFactory;
ELSE
	getSynchronizedObjectListFactory := THIS^.defaultFactories;
END_IF
THIS^.lockObjectSyncList.Leave();

The FactoryProvider class is now designed so that our factories are returned as default factories, but it is possible to inject other factories into the provider. The artificial restriction that there can only be one valid factory for each type is just to keep the example simple.