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