diff --git a/.gitattributes b/.gitattributes index f4a30aaf44c30053e9c3bad5721c456dd143ce73..9210b46cec7c03325a57718acaa16a71c6611619 100644 --- a/.gitattributes +++ b/.gitattributes @@ -197,6 +197,8 @@ MAC/GCF/_CoreComps/TM/test/Echo_Protocol.prot -text svneol=native#application/oc MAC/GCF/_CoreComps/TM/test/Makefile.am -text svneol=native#application/octet-stream MAC/GCF/_CoreComps/TM/test/tutorial.ns.in -text svneol=native#application/octet-stream MAC/GCF/_CoreComps/TM/test/tutorial.top.in -text svneol=native#application/octet-stream +MAC/GCF/_PAL/PA/src/Makefile.am -text svneol=native#application/octet-stream +MAC/GCF/_PAL/PA/src/PA_Protocol.prot -text svneol=native#application/octet-stream MAC/GCF/configure.in -text svneol=native#application/octet-stream MAC/GCF/src/Makefile.am -text svneol=native#application/octet-stream MAC/MACCommon/autogen/protocol.tpl -text svneol=native#application/octet-stream diff --git a/MAC/GCF/_PAL/PA/src/GPA_Controller.cc b/MAC/GCF/_PAL/PA/src/GPA_Controller.cc new file mode 100644 index 0000000000000000000000000000000000000000..dea3113cefb9a114c1271908efe7691e274d55d1 --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/GPA_Controller.cc @@ -0,0 +1,377 @@ +//# GPA_Controller.cc: +//# +//# Copyright (C) 2002-2003 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#include <GPA_Controller.h> +#include <GPA_PropertySet.h> +#include <stdio.h> +#include <PA_Protocol.ph> + +#define CHECK_REQUEST(p, e) \ + if (!mayContinue(e, p)) break; + +static string sPATaskName("PA"); + +GPAController::GPAController() : + GCFTask((State)&GPAController::initial, sPATaskName), + _isBusy(false), + _isRegistered(false), + _counter(0) +{ + // register the protocol for debugging purposes + registerProtocol(PA_PROTOCOL, PA_PROTOCOL_signalnames); + + // initialize the port + _pmlPortProvider.init(*this, "server", GCFPortInterface::MSPP, PA_PROTOCOL); +} + +GPAController::~GPAController() +{ +} + +GCFEvent::TResult GPAController::initial(GCFEvent& e, GCFPortInterface& p) +{ + GCFEvent::TResult status = GCFEvent::HANDLED; + + switch (e.signal) + { + case F_INIT: + break; + + case F_ENTRY: + case F_TIMER: + _pmlPortProvider.open(); + break; + + case F_CONNECTED: + TRAN(GPAController::connected); + break; + + case F_DISCONNECTED: + if (&p == &_pmlPortProvider) + _pmlPortProvider.setTimer(1.0); // try again after 1 second + break; + + default: + status = GCFEvent::NOT_HANDLED; + break; + } + + return status; +} + +GCFEvent::TResult GPAController::connected(GCFEvent& e, GCFPortInterface& p) +{ + GCFEvent::TResult status = GCFEvent::HANDLED; + + switch (e.signal) + { + case F_DISCONNECTED: + if (&p == &_pmlPortProvider) + { + //TODO: find out this can realy happend + } + else + { + p.close(); + } + break; + + case F_CLOSED: + { + CHECK_REQUEST(p, e) + GPAPropertySet* pPropSet(0); + _counter = 0; + for (TPropertySets::iterator iter = _propertySets.begin(); + iter != _propertySets.end(); ++iter) + { + pPropSet = iter->second; + assert(pPropSet); + if (pPropSet->isOwner(p) || pPropSet->knowsClient(p)) + { + // these property sets will be deleted after they will be unregistered + // correctly + _counter++; + } + pPropSet->deleteClient(p); + } + _pmlPortProvider.setTimer(0, 0, 0, 0, (void*) &p); + break; + } + case F_CONNECTED: + _pmlPorts.push_back(&p); + break; + + case PA_LOAD_PROP_SET: + { + CHECK_REQUEST(p, e) + PALoadPropSetEvent request(e); + GPAPropertySet* pPropSet = findPropSet(request.scope); + if (pPropSet) + { + pPropSet->load(request, p); + } + else + { + PAPropSetLoadedEvent response; + response.seqnr = request.seqnr; + response.result = PA_PROP_SET_NOT_EXISTS; + sendAndNext(response); + } + break; + } + case PA_UNLOAD_PROP_SET: + { + CHECK_REQUEST(p, e) + PAUnloadPropSetEvent request(e); + GPAPropertySet* pPropSet = findPropSet(request.scope); + if (pPropSet) + { + pPropSet->unload(request, p); + } + else + { + PAPropSetUnloadedEvent response; + response.seqnr = request.seqnr; + response.result = PA_PROP_SET_NOT_EXISTS; + sendAndNext(response); + } + break; + } + case PA_CONF_PROP_SET: + { + CHECK_REQUEST(p, e) + PAConfPropSetEvent request(e); + GPAPropertySet* pPropSet = findPropSet(request.scope); + if (pPropSet) + { + pPropSet->configure(request); + } + else + { + PAPropSetConfEvent response; + response.seqnr = request.seqnr; + response.apcName = request.apcName; + response.result = PA_PROP_SET_NOT_EXISTS; + sendAndNext(response); + } + break; + } + case PA_REGISTER_SCOPE: + { + CHECK_REQUEST(p, e) + PARegisterScopeEvent request(e); + GPAPropertySet* pPropSet = findPropSet(request.scope); + if (pPropSet) + { + PAScopeRegisteredEvent response; + response.seqnr = request.seqnr; + response.result = PA_PROP_SET_ALLREADY_EXISTS; + sendAndNext(response); + } + else + { + pPropSet = new GPAPropertySet(*this, p); + _propertySets[request.scope] = pPropSet; + pPropSet->enable(request); + } + break; + } + case PA_UNREGISTER_SCOPE: + { + CHECK_REQUEST(p, e) + PAUnregisterScopeEvent request(e); + GPAPropertySet* pPropSet = findPropSet(request.scope); + if (pPropSet) + { + pPropSet->disable(request); + } + else + { + PAScopeUnregisteredEvent response; + response.seqnr = request.seqnr; + response.result = PA_PROP_SET_NOT_EXISTS; + sendAndNext(response); + } + break; + } + case PA_PROP_SET_LINKED: + { + PAPropSetLinkedEvent response(e); + GPAPropertySet* pPropSet = findPropSet(response.scope); + assert(pPropSet); + pPropSet->linked(response); + break; + } + case PA_PROP_SET_UNLINKED: + { + PAPropSetUnlinkedEvent response(e); + GPAPropertySet* pPropSet = findPropSet(response.scope); + assert(pPropSet); + pPropSet->unlinked(response); + break; + } + case F_ACCEPT_REQ: + { + GCFTCPPort* pNewPMLPort = new GCFTCPPort(); + pNewPMLPort->init(*this, "pa", GCFPortInterface::SPP, PA_PROTOCOL); + _pmlPortProvider.accept(*pNewPMLPort); + break; + } + case F_TIMER: + { + if (&p == &_pmlPortProvider) + { + GCFTimerEvent* pTimer = (GCFTimerEvent*)(&e); + if (_deletePortTimId == pTimer->id) + { + GCFPortInterface* pPort = (GCFPortInterface*)(pTimer->arg); + if (pPort) + { + _pmlPorts.remove(pPort); + delete pPort; + } + } + else + { + GPAPropertySet* pPropSet = (GPAPropertySet*)(pTimer->arg); + if (pPropSet) + { + delete pPropSet; + } + } + _counter--; + if (_counter == 0) + { + GCFPortInterface* pPort = _requestManager.getOldestRequestPort(); + GCFEvent* pEvent = _requestManager.getOldestRequest(); + _isBusy = false; + + if (pPort) // new request available? + { + _isRegistered = true; + dispatch(*pEvent, *pPort); + } + + } + } + break; + } + + default: + status = GCFEvent::NOT_HANDLED; + break; + } + + return status; +} + +bool GPAController::mayContinue(GCFEvent& e, GCFPortInterface& p) +{ + bool result(false); + if (!_isRegistered) + _requestManager.registerRequest(p, e); + + _isRegistered = false; + if (!_isBusy) + { + _isBusy = true; + result = true; + } + return result; +} + +void GPAController::sendAndNext(GCFEvent& e) +{ + GCFPortInterface* pPort = _requestManager.getOldestRequestPort(); + assert(pPort); + GCFEvent* pEvent = _requestManager.getOldestRequest(); + assert(pEvent); + if (pEvent->signal == F_CLOSED) + { + // all responses, which are the result of a closed port will handled here + assert (e.signal == PA_PROP_SET_UNLOADED || e.signal == PA_SCOPE_UNREGISTERED); + _counter--; // counter was set in connected method (signal F_CLOSED) + if (_counter == 0) + { + // all responses are received now + // the port and ass. prop. sets will be deleted from administration here + // and must then be destructed in a different context. + // So 0 timers will be used to force a context switch + list<string> propSetsToDelete; + GPAPropertySet* pPropSet(0); + for (TPropertySets::iterator iter = _propertySets.begin(); + iter != _propertySets.end(); ++iter) + { + pPropSet = iter->second; + assert(pPropSet); + if (pPropSet->mayDelete()) + { + // reuses the counter for counting started timers + _counter++; + // add the scope of the prop. set to be deleted + propSetsToDelete.push_back(iter->first); + _pmlPortProvider.setTimer(0, 0, 0, 0, (void*) pPropSet); + } + } + for (list<string>::iterator iter = propSetsToDelete.begin(); + iter != propSetsToDelete.end(); ++iter) + { + _propertySets.erase(*iter); + } + // id's of the above started timers always will be different to the following + // received id because they are started in the same context + _requestManager.deleteRequestsOfPort(*pPort); + _deletePortTimId = _pmlPortProvider.setTimer(0, 0, 0, 0, (void*) pPort); + _pmlPorts.remove(pPort); + // reuses the counter for counting started timers + _counter++; + } + } + else + { + // normal use + if (pPort->isConnected()) + { + pPort->send(e); + } + doNextRequest(); + } +} + +void GPAController::doNextRequest() +{ + _requestManager.deleteOldestRequest(); + GCFPortInterface* pPort = _requestManager.getOldestRequestPort(); + GCFEvent* pEvent = _requestManager.getOldestRequest(); + _isBusy = false; + if (pPort) // new action available ? + { + _isRegistered = true; + dispatch(*pEvent, *pPort); + } +} + +GPAPropertySet* GPAController::findPropSet(const string& scope) const +{ + TPropertySets::const_iterator iter = _propertySets.find(scope); + return (iter != _propertySets.end() ? iter->second : 0); +} diff --git a/MAC/GCF/_PAL/PA/src/GPA_Controller.h b/MAC/GCF/_PAL/PA/src/GPA_Controller.h new file mode 100644 index 0000000000000000000000000000000000000000..8623cd59ca28e99982404d5e3604f1b33d2e2c03 --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/GPA_Controller.h @@ -0,0 +1,76 @@ +//# GPA_Controller.h: main class of the Property Agent +//# +//# Copyright (C) 2002-2003 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#ifndef GPA_CONTROLLER_H +#define GPA_CONTROLLER_H + +#include <GPA_Defines.h> +#include <GPA_RequestManager.h> +#include <GCF/TM/GCF_Task.h> +#include <GCF/TM/GCF_TCPPort.h> + +/** + This is the main class of the Property Agent. It uses a number of helper + classes to manage PML requests, registered scopes and use counts of created + properties. The assigned port provider supports the possibility to accept + more than one connect request from different clients (PML). +*/ + +class GCFEvent; +class GCFPortInterface; +class GPAPropertySet; + +class GPAController : public GCFTask +{ + public: + GPAController(); + virtual ~GPAController(); + + private: // state methods + GCFEvent::TResult initial(GCFEvent& e, GCFPortInterface& p); + GCFEvent::TResult connected(GCFEvent& e, GCFPortInterface& p); + + private: // helper methods + friend class GPAPropertySet; + bool mayContinue(GCFEvent& e, GCFPortInterface& p); + void sendAndNext(GCFEvent& e); + void doNextRequest(); + GPAPropertySet* findPropSet(const string& scope) const; + + private: // data members + typedef map<string /*scope*/, GPAPropertySet*> TPropertySets; + TPropertySets _propertySets; + + GPARequestManager _requestManager; + + list<GCFPortInterface*> _pmlPorts; + GCFTCPPort _pmlPortProvider; + + private: // admin. data members + bool _isBusy; + bool _isRegistered; + long _deletePortTimId; + unsigned int _counter; + +}; + +#endif diff --git a/MAC/GCF/_PAL/PA/src/GPA_Defines.h b/MAC/GCF/_PAL/PA/src/GPA_Defines.h new file mode 100644 index 0000000000000000000000000000000000000000..c51d43a7110d32968a51d89f9e650c52b0bb790d --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/GPA_Defines.h @@ -0,0 +1,61 @@ +//# GPA_Defines.h: preprocessor definitions of various constants +//# +//# Copyright (C) 2002-2003 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#ifndef GPA_DEFINES_H +#define GPA_DEFINES_H + +//#define LOFARLOGGER_PACKAGE "MAC.GCF.PAL.PA.Logger" + +#include <GCF/GCF_Defines.h> + +class GCFPValue; + +enum TPAResult { + PA_NO_ERROR, + PA_UNKNOWN_ERROR, + PA_SCOPE_ALREADY_REGISTERED, + PA_PROP_SET_GONE, + PA_MISSING_PROPS, + PA_PROP_NOT_VALID, + PA_UNABLE_TO_LOAD_APC, + PA_NO_TYPE_SPECIFIED_IN_APC, + PA_EMPTY_SCOPE, + PA_SCADA_ERROR, + PA_SAL_ERROR, + PA_MACTYPE_UNKNOWN, + PA_PROP_SET_NOT_EXISTS, + PA_PROP_SET_ALLREADY_EXISTS, + PA_DPTYPE_UNKNOWN, + PA_PS_ALLREADY_EXISTS, + PA_INTERNAL_ERROR, + PA_WRONG_STATE, + PA_PS_NOT_EXISTS +}; + +typedef struct +{ + string name; + GCFPValue* pValue; + bool defaultSet; +} TAPCProperty; + +#endif diff --git a/MAC/GCF/_PAL/PA/src/GPA_Main.cc b/MAC/GCF/_PAL/PA/src/GPA_Main.cc new file mode 100644 index 0000000000000000000000000000000000000000..20d7cf7d493c662e27fdeb74e956510393433b3d --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/GPA_Main.cc @@ -0,0 +1,37 @@ +//# GPA_Main.cc: +//# +//# Copyright (C) 2002-2003 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#include <GPA_Controller.h> +#include <GCF/GCF_Control.h> + +int main(int argC, char *argV[]) +{ + GCFTask::init(argC, argV); + + GPAController propertyAgent; + + propertyAgent.start(); // make initial transition + + GCFTask::run(); + + return 0; +} diff --git a/MAC/GCF/_PAL/PA/src/GPA_PropertySet.cc b/MAC/GCF/_PAL/PA/src/GPA_PropertySet.cc new file mode 100644 index 0000000000000000000000000000000000000000..2c245b9bdb479954fce7e763f056e3a1d5296a09 --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/GPA_PropertySet.cc @@ -0,0 +1,531 @@ +//# GPA_PropertySet.cc: +//# +//# Copyright (C) 2002-2003 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#include "GPA_PropertySet.h" +#include "GPA_Controller.h" +#include <strings.h> +#include <stdio.h> +#include <unistd.h> + + +GPAPropertySet::GPAPropertySet(GPAController& controller, GCFPortInterface& serverPort) : + _controller(controller), + _usecount(0), + _name(""), + _type(""), + _serverPort(serverPort), + _isTemporary(true), + _state(S_DISABLED), + _counter(0), + _savedResult(PA_NO_ERROR), + _savedSeqnr(0) +{ +} + +GPAPropertySet::~GPAPropertySet() +{ +} + +void GPAPropertySet::enable(PARegisterScopeEvent& request) +{ + PAScopeRegisteredEvent response; + response.seqnr = request.seqnr; + response.result = PA_NO_ERROR; + switch (_state) + { + case S_DISABLED: + { + _state = S_ENABLING; + assert(_psClients.size() == 0); + _name = request.scope; + _type = request.type; + _isTemporary = request.isTemporary; + TSAResult saResult(SA_NO_ERROR); + if (!typeExists(_type)) + { + LOG_INFO(LOFAR::formatString ( + "Type %s is not knwon in the PVSS DB!", + _type.c_str())); + response.result = PA_DPTYPE_UNKNOWN; + } + else if (dpeExists(_name) && _isTemporary) + { + LOG_INFO(LOFAR::formatString ( + "Temporary DP '%s' already exists!", + _type.c_str())); + response.result = PA_PS_ALLREADY_EXISTS; + } + else if (!dpeExists(_name) && !_isTemporary) + { + LOG_INFO(LOFAR::formatString ( + "Permanent DP '%s' does not exists!", + _type.c_str())); + response.result = PA_PS_NOT_EXISTS; + } + else if (_isTemporary) + { + if ((saResult = dpCreate(_name + string("_temp"), string("GCFTempRef"))) != SA_NO_ERROR) + { + if (saResult == SA_DPTYPE_UNKNOWN) + { + LOG_FATAL("Please check the existens of dpType 'GCFTempRef' in PVSS DB!!!"); + } + response.result = PA_INTERNAL_ERROR; + } + } + if (response.result != PA_NO_ERROR) + { + // not enabled due to errors; respond with error + _state = S_DISABLED; + _controller.sendAndNext(response); + } + break; + } + default: + wrongState("enable"); + response.result = PA_WRONG_STATE; + _controller.sendAndNext(response); + break; + } +} + +void GPAPropertySet::disable(PAUnregisterScopeEvent& request) +{ + PAScopeUnregisteredEvent response; + response.seqnr = request.seqnr; + response.result = PA_NO_ERROR; + _savedSeqnr = request.seqnr; + switch (_state) + { + case S_LINKED: + { + PAPropSetGoneEvent indication; + indication.scope = _name; + GCFPortInterface* pPSClientPort; + for (TPSClients::iterator iter = _psClients.begin(); + iter != _psClients.end(); ++iter) + { + pPSClientPort = iter->pPSClientPort; + assert(pPSClientPort); + + if (pPSClientPort->isConnected()) + { + pPSClientPort->send(indication); + } + } + // list will be automatically cleaned up on destruction of this class + } + // intentional fall through + case S_ENABLED: + { + _state = S_DISABLING; + _counter = 0; + if (_isTemporary) + { + if (dpeExists(_name + string("_temp"))) + { + LOG_INFO(LOFAR::formatString ( + "%s_temp still exists! Will be removed too!", + _name.c_str())); + if (dpDelete(_name + string("_temp")) != SA_NO_ERROR) + { + response.result = PA_INTERNAL_ERROR; + } + else + { + _counter += 1; + } + } + if (dpeExists(_name)) + { + LOG_INFO(LOFAR::formatString ( + "%s still exists! Will be removed too!", + _name.c_str())); + if (dpDelete(_name) != SA_NO_ERROR) + { + response.result = PA_INTERNAL_ERROR; + } + else + { + _counter += 1; + } + } + } + + if (_counter == 0) + { + _state = S_DISABLED; + _controller.sendAndNext(response); + } + else + { + _savedResult = response.result; + } + _usecount = 0; + break; + } + default: + wrongState("disable"); + response.result = PA_WRONG_STATE; + _controller.sendAndNext(response); + break; + } +} + +void GPAPropertySet::load(PALoadPropSetEvent& request, GCFPortInterface& p) +{ + PAPropSetLoadedEvent response; + response.seqnr = request.seqnr; + response.result = PA_NO_ERROR; + _savedSeqnr = request.seqnr; + switch (_state) + { + case S_ENABLED: + { + _state = S_LINKING; + assert(_usecount == 0); + if (_isTemporary) + { + if (dpCreate(_name, _type) != SA_NO_ERROR) + { + response.result = PA_INTERNAL_ERROR; + } + } + else + { + linkPropSet(); + } + if (response.result != PA_NO_ERROR) + { + _controller.sendAndNext(response); + _state = S_ENABLED; + } + else + { + // In case a loaded property set will be disabled by the owner (server MCA), + // we need a mechanism to inform all client MCA's (which has loaded + // this property set). + // That's why we remember the port of the requestor (client MCA). The + // combination of the following two reasons explains the need of extending + // the port with a load counter: + // - a requestor can has loaded the same property set (same scope) + // more than once (on different places) at the same time and + // - we need to know when this requestor may be deleted from the + // clientport list and thus not needed to be informed about disabling + // the prop. set anymore. + // If client has allready loaded a property set with this scope (_name), + // only the counter needed to be increased. + // On unloading the counter will be decreased and if counter + // is 0 the requestor can be deleted from the list. Then the requestor + // not needed to be and also will not be informed about disabling the + // property set. + TPSClient* pPSClient = findClient(p); + if (pPSClient) + { + pPSClient->count++; + } + else // client not known yet + { + TPSClient psClient; + psClient.pPSClientPort = &p; + psClient.count = 1; + _psClients.push_back(psClient); + } + } + break; + } + case S_LINKED: + assert(dpeExists(_name)); + _usecount++; + _controller.sendAndNext(response); + break; + + default: + wrongState("load"); + response.result = PA_WRONG_STATE; + _controller.sendAndNext(response); + break; + } +} + +void GPAPropertySet::unload(PAUnloadPropSetEvent& request, const GCFPortInterface& p) +{ + PAPropSetUnloadedEvent response; + response.seqnr = request.seqnr; + response.result = PA_NO_ERROR; + _savedSeqnr = request.seqnr; + _savedResult = PA_NO_ERROR; + switch (_state) + { + case S_LINKED: + { + _usecount--; + if (_usecount == 0) + { + _state = S_UNLINKING; + if (_isTemporary) + { + _counter = 0; + if (dpDelete(_name) != SA_NO_ERROR) + { + response.result = PA_INTERNAL_ERROR; + } + else + { + _counter += 1; + } + if (dpDelete(_name + string("_temp")) != SA_NO_ERROR) + { + response.result = PA_INTERNAL_ERROR; + } + else + { + _counter += 1; + } + } + else + { + unlinkPropSet(); + } + } + else + { + _controller.sendAndNext(response); + } + + if (response.result != PA_NO_ERROR) + { + if (_counter == 0) + { + _state = S_ENABLED; + _controller.sendAndNext(response); + } + else + { + _savedResult = response.result; + } + } + // decrease the load counter and remove the client (if counter == 0), + // see also 'load' + TPSClient* pPSClient = findClient(p); + if (pPSClient) + { + pPSClient->count--; + if (pPSClient->count == 0) + { + _psClients.erase(*pPSClient); + } + } + break; + } + + default: + wrongState("unload"); + response.result = PA_WRONG_STATE; + _controller.sendAndNext(response); + break; + } +} + +void GPAPropertySet::configure(PAConfPropSetEvent& request) +{ +} + +void GPAPropertySet::linked(PAPropSetLinkedEvent& response) +{ + PAPropSetLoadedEvent loadedResponse; + loadedResponse.seqnr = _savedSeqnr; + if (_state == S_LINKING) + { + _state = S_LINKED; + loadedResponse.result = response.result; + } + else + { + _state = S_ENABLED; + wrongState("linked"); + loadedResponse.result = PA_WRONG_STATE; + } + _controller.sendAndNext(loadedResponse); +} + +void GPAPropertySet::unlinked(PAPropSetUnlinkedEvent& response) +{ + PAPropSetUnloadedEvent unloadedResponse; + unloadedResponse.seqnr = _savedSeqnr; + if (_state == S_UNLINKING) + { + unloadedResponse.result = (_savedResult != PA_NO_ERROR ? _savedResult : response.result); + } + else + { + wrongState("unlinked"); + unloadedResponse.result = PA_WRONG_STATE; + } + _state = S_ENABLED; + _controller.sendAndNext(unloadedResponse); +} + +void GPAPropertySet::deleteClient(const GCFPortInterface& p) +{ + if (&p == &_serverPort) + { + // This property set must be disabled because the server does not + // exists anymore. + // So pretend a disable request is received + PAUnregisterScopeEvent request; + request.scope = _name; + request.seqnr = 0; + disable(request); + } + else + { + // This means that all load requests of client 'p' have to be undone. + // So pretend a unload request is received + TPSClient* pPSClient = findClient(p); + if (pPSClient) + { + // this manipulation of the _usecount and the load counter pretends + // that this is the last unload request of the client 'p' for this + // property set + _usecount -= (pPSClient->count - 1); + pPSClient->count = 1; + + PAUnloadPropSetEvent request; + request.scope = _name; + request.seqnr = 0; + unload(request, p); + } + } +} + +void GPAPropertySet::dpCreated(const string& dpName) +{ + switch (_state) + { + case S_ENABLING: + assert(dpName == (_name + string("_temp"))); + _state = S_ENABLED; + break; + case S_LINKING: + assert(dpName == _name); + linkPropSet(); + break; + default: + wrongState("dpCreated"); + break; + } +} + +void GPAPropertySet::dpDeleted(const string& /*dpName*/) +{ + switch (_state) + { + case S_DISABLING: + _counter--; + if (_counter == 0) + { + _state = S_DISABLED; + PAScopeUnregisteredEvent response; + response.seqnr = _savedSeqnr; + response.result = _savedResult; + _controller.sendAndNext(response); + } + break; + case S_UNLINKING: + _counter--; + if (_counter == 0) + { + unlinkPropSet(); + } + break; + default: + wrongState("dpDeleted"); + break; + } +} + +void GPAPropertySet::linkPropSet() +{ + assert(dpeExists(_name)); + assert(_serverPort.isConnected()); + PALinkPropSetEvent linkRequest; + linkRequest.scope = _name; + _serverPort.send(linkRequest); +} + +void GPAPropertySet::unlinkPropSet() +{ + assert(dpeExists(_name)); + assert(_serverPort.isConnected()); + PAUnlinkPropSetEvent unlinkRequest; + unlinkRequest.scope = _name; + _serverPort.send(unlinkRequest); +} + +GPAPropertySet::TPSClient* GPAPropertySet::findClient(const GCFPortInterface& p) +{ + TPSClient* pPSClient(0); + for (TPSClients::iterator iter = _psClients.begin(); + iter != _psClients.end(); ++iter) + { + if (iter->pPSClientPort == &p) + { + pPSClient = &(*iter); + break; + } + } + return pPSClient; +} + +void GPAPropertySet::wrongState(const char* request) +{ + char* stateString(0); + switch (_state) + { + case S_DISABLED: + stateString = "DISABLED"; + break; + case S_DISABLING: + stateString = "DISABLING"; + break; + case S_ENABLED: + stateString = "ENABLED"; + break; + case S_ENABLING: + stateString = "ENABLING"; + break; + case S_LINKING: + stateString = "LINKING"; + break; + case S_UNLINKING: + stateString = "UNLINKING"; + break; + case S_LINKED: + stateString = "LINKED"; + break; + } + LOG_WARN(LOFAR::formatString ( + "Could not perform '%s' on property set '%s'. Wrong state: %s", + request, + stateString)); +} diff --git a/MAC/GCF/_PAL/PA/src/GPA_PropertySet.h b/MAC/GCF/_PAL/PA/src/GPA_PropertySet.h new file mode 100644 index 0000000000000000000000000000000000000000..29a87e7df9bd579b7ecb83d2ca97c8f54c289224 --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/GPA_PropertySet.h @@ -0,0 +1,99 @@ +//# GPA_PropertySet.h: manages the properties with its use count +//# +//# Copyright (C) 2002-2003 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#ifndef GPA_PROPERTYSET_H +#define GPA_PROPERTYSET_H + +#include <GPA_Defines.h> +#include <GSA_Service.h> +#include <PA_Protocol.ph> +#include <Common/lofar_list.h> + +/** + This class manages the properties with its use count, which are created + (resp. deleted) by means of the base class GSAService. +*/ + +class GPAController; +class GCFPortInterface; + +class GPAPropertySet : public GSAService +{ + public: + GPAPropertySet(GPAController& controller, GCFPortInterface& serverPort); + virtual ~GPAPropertySet(); + + void enable(PARegisterScopeEvent& request); + void disable(PAUnregisterScopeEvent& request); + void load(PALoadPropSetEvent& request, GCFPortInterface& p); + void unload(PAUnloadPropSetEvent& request, const GCFPortInterface& p); + void configure(PAConfPropSetEvent& request); + + void linked(PAPropSetLinkedEvent& response); + void unlinked(PAPropSetUnlinkedEvent& response); + + void deleteClient(const GCFPortInterface& p); + + bool isOwner(const GCFPortInterface& p) const { return (&p == &_serverPort); } + bool mayDelete() const { return (_state == S_DISABLED); } + bool knowsClient(const GCFPortInterface& p) { return (findClient(p) != 0); } + + protected: + void dpCreated(const string& propName); + void dpDeleted(const string& propName); + inline void dpeValueGet(const string& /*propName*/, const GCFPValue& /*value*/) {}; + inline void dpeValueChanged(const string& /*propName*/, const GCFPValue& /*value*/) {}; + inline void dpeSubscribed(const string& /*propName*/) {}; + inline void dpeUnsubscribed(const string& /*propName*/) {}; + + private: // helper methods + typedef struct + { + GCFPortInterface* pPSClientPort; + unsigned short count; + operator == + } TPSClient; + + void linkPropSet(); + void unlinkPropSet(); + void wrongState(const char* request); + TPSClient* findClient(const GCFPortInterface& p); + + private: // data members + GPAController& _controller; + unsigned short _usecount; + string _name; + string _type; + GCFPortInterface& _serverPort; + typedef list<TPSClient> TPSClients; + TPSClients _psClients; + bool _isTemporary; + + private: // admin. data members + typedef enum TSTATE {S_ENABLED, S_ENABLING, S_DISABLED, S_DISABLING, S_LINKING, S_LINKED, S_UNLINKING}; + TSTATE _state; + unsigned int _counter; + TPAResult _savedResult; + unsigned short _savedSeqnr; +}; + +#endif diff --git a/MAC/GCF/_PAL/PA/src/GPA_RequestManager.cc b/MAC/GCF/_PAL/PA/src/GPA_RequestManager.cc new file mode 100644 index 0000000000000000000000000000000000000000..645774f009b873db3f006fb7c9ba12b0c8dbcc09 --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/GPA_RequestManager.cc @@ -0,0 +1,108 @@ +//# GPA_RequestManager.cc: +//# +//# Copyright (C) 2002-2003 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#include "GPA_RequestManager.h" +#include <GCF/GCF_Event.h> + +GPARequestManager::GPARequestManager() +{ +} + +GPARequestManager::~GPARequestManager() +{ + deleteAllRequests(); +} + +void GPARequestManager::registerRequest(GCFPortInterface& requestPort, const GCFEvent& e) +{ + TRequest request; + request.pRPort = &requestPort; + request.pEvent = new char[sizeof(e) + e.length]; + memcpy(request.pEvent, (const char*) &e, sizeof(e) + e.length); + + _requests.push_back(request); +} + +GCFEvent* GPARequestManager::getOldestRequest() +{ + if (_requests.size() > 0) + { + TRequest* pRequest = &_requests.front(); + return (GCFEvent*) (pRequest->pEvent); + } + else + return 0; +} + +GCFPortInterface* GPARequestManager::getOldestRequestPort() +{ + if (_requests.size() > 0) + { + TRequest* pRequest = &_requests.front(); + return pRequest->pRPort; + } + else + return 0; +} + +void GPARequestManager::deleteOldestRequest() +{ + if (_requests.size() > 0) + { + TRequest* pRequest = &_requests.front(); + if (pRequest->pEvent) + delete [] pRequest->pEvent; + } + + _requests.pop_front(); +} + +void GPARequestManager::deleteRequestsOfPort(const GCFPortInterface& requestPort) +{ + TRequest* pRequest; + for (list<TRequest>::iterator iter = _requests.begin(); + iter != _requests.end(); ++iter) + { + pRequest = &(*iter); + if (pRequest) + { + if (pRequest->pRPort == &requestPort) + { + if (pRequest->pEvent) + delete [] pRequest->pEvent; + iter = _requests.erase(iter); + --iter; + } + } + } +} + +void GPARequestManager::deleteAllRequests() +{ + for (list<TRequest>::iterator pRequest = _requests.begin(); + pRequest != _requests.end(); ++pRequest) + { + if (pRequest->pEvent) + delete [] pRequest->pEvent; + } + _requests.clear(); +} diff --git a/MAC/GCF/_PAL/PA/src/GPA_RequestManager.h b/MAC/GCF/_PAL/PA/src/GPA_RequestManager.h new file mode 100644 index 0000000000000000000000000000000000000000..00621fdac5fc16384792424cafb304145096defa --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/GPA_RequestManager.h @@ -0,0 +1,62 @@ +//# GPA_RequestManager.h: manages a FIFO queue of requests of the PA +//# +//# Copyright (C) 2002-2003 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# $Id$ + +#ifndef GPA_REQUESTMANAGER_H +#define GPA_REQUESTMANAGER_H + +#include <GPA_Defines.h> +#include <Common/lofar_list.h> + +/** + This class manages a FIFO queue of requests, which + can be received from a PML and not handled immediately. +*/ +class GCFPortInterface; +class GCFEvent; + +class GPARequestManager +{ + public: + GPARequestManager(); + virtual ~GPARequestManager(); + + void registerRequest(GCFPortInterface& requestPort, const GCFEvent& e); + GCFEvent* getOldestRequest(); + GCFPortInterface* getOldestRequestPort(); + + void deleteOldestRequest(); + void deleteRequestsOfPort(const GCFPortInterface& requestPort); + void deleteAllRequests(); + + private: // helper methods + + private: // data members + typedef struct + { + GCFPortInterface* pRPort; + char* pEvent; + } TRequest; + + list<TRequest> _requests; +}; + +#endif diff --git a/MAC/GCF/_PAL/PA/src/Makefile.am b/MAC/GCF/_PAL/PA/src/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..f62e627b848ca597c350844aa89b9acd4f68e165 --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/Makefile.am @@ -0,0 +1,59 @@ +AUTOGEN = autogen +SUFFIXES = .ph +%.ph: %.prot + $(AUTOGEN) -L $(top_srcdir)/../../MACCommon/autogen $< && \ + chmod a+w $@ + +DOCHDRS = \ + GPA_Controller.h \ + GPA_PropertySet.h \ + GPA_RequestManager.h \ + GPA_Defines.h + +noinst_LTLIBRARIES = libpa.la + +libpa_la_SOURCES= $(DOCHDRS) \ + GPA_Controller.cc \ + GPA_PropertySet.cc \ + GPA_RequestManager.cc \ + PA_Protocol.cc + +libpa_la_CPPFLAGS= -I$(top_srcdir)/include/GCF/PAL \ + -I$(top_srcdir)/SAL/src + + +bin_PROGRAMS = PropertyAgent + +PropertyAgent_SOURCES = GPA_Main.cc +PropertyAgent_LDADD = libpa.la $(LOFAR_DEPEND) \ + $(top_builddir)/SAL/src/libsal.la + +PropertyAgent_DEPENDENCIES = libpa.la $(LOFAR_DEPEND) \ + $(top_builddir)/SAL/src/libsal.la + +PropertyAgent_CPPFLAGS= -I$(top_srcdir)/include/GCF/PAL \ + -I$(top_srcdir)/SAL/src + +BUILT_SOURCES = \ + PA_Protocol.ph \ + mac.ns \ + mac.top \ + log4cplus.properties + +EXTRA_DIST = \ + PA_Protocol.ph \ + mac.ns \ + mac.top \ + log4cplus.properties + +%.properties: $(MAC_CONFIG)/%.properties + cp $< $@ + +%.ns: $(MAC_CONFIG)/%.ns + cp $< $@ + +%.top: $(MAC_CONFIG)/%.top + cp $< $@ + +include $(lofar_sharedir)/Makefile.common + diff --git a/MAC/GCF/_PAL/PA/src/PA_Protocol.prot b/MAC/GCF/_PAL/PA/src/PA_Protocol.prot new file mode 100644 index 0000000000000000000000000000000000000000..d04c06728a0fdb275108334f3845813d5d4e6c59 --- /dev/null +++ b/MAC/GCF/_PAL/PA/src/PA_Protocol.prot @@ -0,0 +1,216 @@ +// +// Protocol definition for the PA server +// +autogen definitions protocol; + +description = "Protocol for the PA server"; +prefix = "PA"; // for the signal names +id = "(F_GCF_PROTOCOL + 1)"; + +// specify extra include files +include = '<GPA_Defines.h>'; + +// +// An "event" has a "signal" and a "dir" (direction) +// and zero or more "param"s. +// "dir" can be one of "IN" or "OUT". +// A "param" has a "name" and a "type". +// +event = { + signal = LOAD_PROP_SET; + dir = IN; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "scope"; + type = "string"; + }; +}; + +event = { + signal = UNLOAD_PROP_SET; + dir = IN; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "scope"; + type = "string"; + }; +}; + +event = { + signal = CONF_PROP_SET; + dir = IN; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "scope"; + type = "string"; + }; + param = { + name = "apcName"; + type = "string"; + }; +}; + +event = { + signal = PROP_SET_LOADED; + dir = OUT; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "result"; + type = "TPAResult"; + }; +}; + +event = { + signal = PROP_SET_UNLOADED; + dir = OUT; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "result"; + type = "TPAResult"; + }; +}; + +event = { + signal = PROP_SET_CONF; + dir = OUT; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "apcName"; + type = "string"; + }; + param = { + name = "result"; + type = "TPAResult"; + }; +}; + +event = { + signal = REGISTER_SCOPE; + dir = IN; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "scope"; + type = "string"; + }; + param = { + name = "type"; + type = "string"; + }; + param = { + name = "isTemporary"; + type = "bool"; + }; +}; + +event = { + signal = UNREGISTER_SCOPE; + dir = IN; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "scope"; + type = "string"; + }; +}; + +event = { + signal = SCOPE_REGISTERED; + dir = OUT; + param = { + name = "seqnr"; + type = "unsigned short"; + }; + param = { + name = "result"; + type = "TPAResult"; + }; +}; + +event = { + signal = SCOPE_UNREGISTERED; + dir = OUT; + param = { + name = "result"; + type = "TPAResult"; + }; + param = { + name = "seqnr"; + type = "unsigned short"; + }; +}; + +event = { + signal = LINK_PROP_SET; + dir = OUT; + param = { + name = "scope"; + type = "string"; + }; +}; + +event = { + signal = UNLINK_PROP_SET; + dir = OUT; + param = { + name = "scope"; + type = "string"; + }; +}; + +event = { + signal = PROP_SET_LINKED; + dir = IN; + param = { + name = "scope"; + type = "string"; + }; + param = { + name = "result"; + type = "TPAResult"; + }; +}; + +event = { + signal = PROP_SET_UNLINKED; + dir = IN; + param = { + name = "scope"; + type = "string"; + }; + param = { + name = "result"; + type = "TPAResult"; + }; +}; + +event = { + signal = PROP_SET_GONE; + dir = OUT; + param = { + name = scope; + type = string; + }; +};