<?xml version="1.0" encoding="utf-8"?>
<tizenModes xmlns="http://www.tizen.org" version="6.0">
<mode name="ex2" type="normal" hidden="true">
- <action ID="1" rule="test.printInt" stopOnErr="true" restrict="lock" priority="-100">PRINT_FOUR</action>
- <action ID="wifiOff" rule="test.printBool" restrict="lock" priority="-100">off</action>
+ <action ID="1" rule="test.printInt" stopOnErr="true" restrict="lock">PRINT_FOUR</action>
+ <action ID="wifiOff" rule="test.printBool" restrict="lock">off</action>
+ <action rule="test.alwaySameValue">test</action>
</mode>
</tizenModes>
class Plugin {
public:
- Plugin()
- {
- }
- virtual ~Plugin()
- {
- }
+ Plugin() = default;
+ virtual ~Plugin() = default;
void setName(const std::string &pluginName)
{
return name;
}
- virtual int set(const std::string &key, int val, PluginAction **piAction)
- {
- return MODES_ERROR_NOT_SUPPORTED;
- }
- virtual int set(const std::string &key, double val, PluginAction **piAction)
- {
- return MODES_ERROR_NOT_SUPPORTED;
- }
- virtual int set(const std::string &key, bool val, PluginAction **piAction)
- {
- return MODES_ERROR_NOT_SUPPORTED;
- }
- virtual int set(const std::string &key, const std::string &val, PluginAction **piAction)
- {
- return MODES_ERROR_NOT_SUPPORTED;
- }
- virtual void undo(PluginAction *piAction)
- {
- if (piAction) {
- piAction->undo();
- delete piAction;
- }
- }
- virtual PluginAction* getUndoAction(const std::string &key, const std::string &info)
- {
- return nullptr;
- }
- virtual std::string serializeAction(PluginAction *piAction)
- {
- if (NULL == piAction)
- return std::string();
+ //It should returns dynamic allocated instance of PluginAction
+ virtual PluginAction* newAction(const std::string &key) = 0;
- return piAction->serialize();
- }
- void freeAction(PluginAction *piAction)
+ //Using destructor of PluginAction without overriding is recommended
+ virtual void deleteAction(PluginAction *piAction)
{
+ //release resources of piAction
delete piAction;
}
private:
- std::string name; /* plugin key */
+ std::string name;
};
- typedef Plugin *create_t();
- typedef void destroy_t(Plugin *);
+ typedef Plugin* (*createFunc)(void);
+ typedef void (*destroyFunc)(Plugin*);
}
class PluginAction {
public:
- PluginAction(const std::string &actionName)
- : name(actionName)
+ PluginAction(const std::string &actionKey)
+ : key(actionKey)
{
}
virtual ~PluginAction() = default;
- std::string getName()
+ std::string getKey()
{
- return name;
+ return key;
}
+
+ //If it is true, the Action is ignored.
+ //It is possible to get the old value in this procedure
+ //because the set() is immediately called after this function
+ virtual bool IsCurrentValue(int val)
+ {
+ return false;
+ }
+ virtual bool IsCurrentValue(double val)
+ {
+ return false;
+ }
+ virtual bool IsCurrentValue(bool val)
+ {
+ return false;
+ }
+ virtual bool IsCurrentValue(const std::string &val)
+ {
+ return false;
+ }
+
+ virtual int set(int val)
+ {
+ return MODES_ERROR_NOT_SUPPORTED;
+ }
+ virtual int set(double val)
+ {
+ return MODES_ERROR_NOT_SUPPORTED;
+ }
+ virtual int set(bool val)
+ {
+ return MODES_ERROR_NOT_SUPPORTED;
+ }
+ virtual int set(const std::string &val)
+ {
+ return MODES_ERROR_NOT_SUPPORTED;
+ }
+
virtual void undo()
{
}
- virtual std::string serialize()
+ virtual std::string getUndoInfo()
{
return std::string();
}
- virtual int parse(const std::string &data)
+ virtual int setUndoInfo(const std::string &info)
{
return MODES_ERROR_NOT_SUPPORTED;
}
virtual int setChangedCallback(valueChangedCB callback, void *userData)
{
+ // The callback should be called when the value is changed(Not Same).
return MODES_ERROR_NOT_SUPPORTED;
}
virtual void unSetChangedCallback(valueChangedCB callback, void *userData)
{
}
- private:
- const std::string name;
+ protected:
+ const std::string key;
};
-
}
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <thread>
-#include <chrono>
-#include <glib.h>
#include "modes_errors.h"
#include "Plugin.h"
#include "PluginAction.h"
public:
TestPlugin();
- ~TestPlugin();
+ ~TestPlugin() override = default;
- int set(const std::string &key, int val, PluginAction **piAction) override;
- int set(const std::string &key, double val, PluginAction **piAction) override;
- int set(const std::string &key, bool val, PluginAction **piAction) override;
- int set(const std::string &key, const std::string &val, PluginAction **piAction) override;
- void undo(PluginAction *piAction) override;
- PluginAction* getUndoAction(const std::string &key, const std::string &info) override;
-private:
- static gboolean changeTimeout(gpointer data)
- {
- RETV_IF(nullptr == data, G_SOURCE_REMOVE);
-
- TestPluginAction *testAction = (TestPluginAction*)data;
- testAction->callChangedCB();
-
- return G_SOURCE_REMOVE;
- }
+ PluginAction* newAction(const std::string &key) override;
+ void deleteAction(PluginAction *piAction) override;
};
-extern "C" API Plugin *objectCreate(void)
+extern "C" API Plugin* objectCreate(void)
{
- return new TestPlugin;
+ return new TestPlugin();
}
extern "C" API void objectDelete(Plugin *plugin)
delete plugin;
}
-
TestPlugin::TestPlugin()
{
setName("test");
}
-TestPlugin::~TestPlugin()
-{
-}
-
-int TestPlugin::set(const std::string &key, int val, PluginAction **piAction)
+PluginAction* TestPlugin::newAction(const std::string &key)
{
- TestPluginAction *testAction = new TestPluginAction(key);
-
- if ("changeAccuracy" == key) {
- DBG("set(%s, %d)", key.c_str(), val);
- } else if ("exactness" == key) {
- DBG("set(%s, %d)", key.c_str(), val);
- } else if ("nightLight" == key) {
- DBG("set(%s, %d)", key.c_str(), val);
- } else if ("printInt" == key) {
- DBG("set(%s, %d)", key.c_str(), val);
- } else if ("sleep" == key) {
- std::this_thread::sleep_for(std::chrono::seconds(val));
- DBG("set(%s, %d)", key.c_str(), val);
- } else if ("sleepErrorReturn" == key) {
- std::this_thread::sleep_for(std::chrono::seconds(val));
- delete testAction;
- DBG("set(%s, %d)", key.c_str(), val);
- return MODES_ERROR_SYSTEM;
- } else if ("changeTime" == key) {
- if (piAction)
- g_timeout_add_seconds(val, changeTimeout, (void*)testAction);
- DBG("set(%s, %d)", key.c_str(), val);
- } else {
- ERR("Unknown key(%s)", key.c_str());
- delete testAction;
- return MODES_ERROR_NOT_SUPPORTED;
- }
-
- if (piAction)
- *piAction = testAction;
- else
- delete testAction;
-
- return MODES_ERROR_NONE;
-}
-
-int TestPlugin::set(const std::string &key, double val, PluginAction **piAction)
-{
- DBG("TestPlugin::set double ( %s, %lf )", key.c_str(), val);
-
- if (piAction) {
- TestPluginAction *testAction = new TestPluginAction(key);
- *piAction = testAction;
- }
- return MODES_ERROR_NONE;
+ return new TestPluginAction(key);
}
-int TestPlugin::set(const std::string &key, bool val, PluginAction **piAction)
+void TestPlugin::deleteAction(PluginAction *piAction)
{
- DBG("TestPlugin::set bool ( %s, %s )", key.c_str(), val ? "true" : "false");
-
- if ("printBool" != key) {
- ERR("Unknown key(%s)", key.c_str());
- return MODES_ERROR_NOT_SUPPORTED;
- }
-
- if (piAction) {
- TestPluginAction *testAction = new TestPluginAction(key);
- *piAction = testAction;
- }
- return MODES_ERROR_NONE;
-}
-
-int TestPlugin::set(const std::string &key, const std::string &val, PluginAction **piAction)
-{
- DBG("TestPlugin::set string ( %s, %s )", key.c_str(), val.c_str());
-
- if (piAction) {
- TestPluginAction *testAction = new TestPluginAction(key);
- *piAction = testAction;
- }
- return MODES_ERROR_NONE;
-}
-
-void TestPlugin::undo(PluginAction *piAction)
-{
- if (piAction) {
- DBG("TestPlugin::undo(Action:%s)", piAction->getName().c_str());
- delete piAction;
- }
-}
-
-PluginAction* TestPlugin::getUndoAction(const std::string &key, const std::string &info)
-{
- // parse the key for making PluginAction
- TestPluginAction *piAction = new TestPluginAction(key);
- piAction->parse(info);
-
- return piAction;
+ //release resource of piAction
+ //Using destructor of PluginAction without overriding is recommended
+ delete piAction;
}
*/
#include "TestPluginAction.h"
+#include <thread>
+#include <chrono>
#include "modes_errors.h"
#include "common/log.h"
#include "common/definitions.h"
MODES_NAMESPACE_USE;
-TestPluginAction::TestPluginAction(const std::string &name)
- : PluginAction(name), cb(nullptr), cbData(nullptr)
+TestPluginAction::TestPluginAction(const std::string &actionKey)
+ : PluginAction(actionKey), cb(nullptr), cbData(nullptr)
{
}
-TestPluginAction::~TestPluginAction()
+bool TestPluginAction::IsCurrentValue(const std::string &val)
{
+ return true;
+}
+
+int TestPluginAction::set(int val)
+{
+ if ("changeAccuracy" == key) {
+ DBG("set(%s, %d)", key.c_str(), val);
+ } else if ("exactness" == key) {
+ DBG("set(%s, %d)", key.c_str(), val);
+ } else if ("nightLight" == key) {
+ DBG("set(%s, %d)", key.c_str(), val);
+ } else if ("printInt" == key) {
+ DBG("set(%s, %d)", key.c_str(), val);
+ } else if ("sleep" == key) {
+ std::this_thread::sleep_for(std::chrono::seconds(val));
+ DBG("set(%s, %d)", key.c_str(), val);
+ } else if ("sleepErrorReturn" == key) {
+ std::this_thread::sleep_for(std::chrono::seconds(val));
+ DBG("set(%s, %d)", key.c_str(), val);
+ return MODES_ERROR_SYSTEM;
+ } else if ("changeTime" == key) {
+ g_timeout_add_seconds(val, changeTimeout, this);
+ DBG("set(%s, %d)", key.c_str(), val);
+ } else {
+ ERR("Unknown key(%s)", key.c_str());
+ return MODES_ERROR_NOT_SUPPORTED;
+ }
+
+ return MODES_ERROR_NONE;
+}
+
+int TestPluginAction::set(double val)
+{
+ DBG("TestPlugin::set double (%s, %lf)", key.c_str(), val);
+
+ if ("printFloat" != key) {
+ ERR("Unknown key(%s)", key.c_str());
+ return MODES_ERROR_NOT_SUPPORTED;
+ }
+ return MODES_ERROR_NONE;
+}
+
+int TestPluginAction::set(bool val)
+{
+ DBG("TestPlugin::set bool (%s, %s)", key.c_str(), val ? "true" : "false");
+
+ if ("printBool" != key) {
+ ERR("Unknown key(%s)", key.c_str());
+ return MODES_ERROR_NOT_SUPPORTED;
+ }
+
+ return MODES_ERROR_NONE;
+}
+
+int TestPluginAction::set(const std::string &val)
+{
+ DBG("TestPlugin::set string (%s, %s)", key.c_str(), val.c_str());
+
+ if ("alwaySameValue" == key) {
+ ERR("key(%s) should not reach here", key.c_str());
+ return MODES_ERROR_NOT_SUPPORTED;
+ }
+
+ return MODES_ERROR_NONE;
}
void TestPluginAction::undo()
{
- INFO("TestPluginAction::undo(%s) is Called", getName().c_str());
+ INFO("TestPluginAction::undo(%s) is Called", getKey().c_str());
}
-std::string TestPluginAction::serialize()
+std::string TestPluginAction::getUndoInfo()
{
- return getName();
+ return getKey();
}
-int TestPluginAction::parse(const std::string &info)
+int TestPluginAction::setUndoInfo(const std::string &info)
{
- DBG("serialized info(%s)", info.c_str());
+ INFO("Undo info(%s)", info.c_str());
return MODES_ERROR_NONE;
}
void TestPluginAction::callChangedCB()
{
- INFO("%s is changed", getName().c_str());
+ INFO("%s is changed", getKey().c_str());
if (cb)
cb(cbData);
}
+
+gboolean TestPluginAction::changeTimeout(gpointer data)
+{
+ RETV_IF(nullptr == data, G_SOURCE_REMOVE);
+
+ TestPluginAction *testAction = (TestPluginAction*)data;
+ testAction->callChangedCB();
+
+ return G_SOURCE_REMOVE;
+}
*/
#pragma once
+#include <glib.h>
#include <string>
#include "PluginAction.h"
#include "common/definitions.h"
class TestPluginAction : public PluginAction {
public:
- TestPluginAction(const std::string &name);
- ~TestPluginAction() override;
+ TestPluginAction(const std::string &actionKey);
+ ~TestPluginAction() override = default;
+ bool IsCurrentValue(const std::string &val) override;
+
+ int set(int val) override;
+ int set(double val) override;
+ int set(bool val) override;
+ int set(const std::string &val) override;
void undo() override;
- std::string serialize() override;
- int parse(const std::string &data) override;
+ std::string getUndoInfo() override;
+ int setUndoInfo(const std::string &data) override;
int setChangedCallback(valueChangedCB callback, void *userData) override;
void unSetChangedCallback(valueChangedCB callback, void *userData) override;
void callChangedCB();
private:
+ static gboolean changeTimeout(gpointer data);
+
valueChangedCB cb;
void *cbData;
};
<desc>It prints boolean value</desc>
<domain>System</domain>
</rule>
- <rule name="test.printDouble" type="float" since="6.0" plugin="test">
+ <rule name="test.printFloat" type="float" since="6.0" plugin="test">
<privilege>http://tizen.org/privilege/systemsettings.admin</privilege>
<desc>It prints double value</desc>
<domain>System</domain>
<desc>Call Change callback after value seconds</desc>
<domain>System</domain>
</rule>
+ <rule name="test.alwaySameValue" type="string" since="6.0">
+ <desc>IsCurrentValue() Always returns true</desc>
+ <domain>System</domain>
+ </rule>
</actionRule>
</tizenModes>
*/
#include "Action.h"
+#include <memory>
#include "mdss.h"
#include "ModesEx.h"
MODES_NAMESPACE_USE;
-Action::Action()
- : isChanged(false), type(SYNC), life(PERMANENT), plugin(nullptr), piAction(nullptr), stopOnErr(false), restriction(NONE), locked(false)
+std::map<std::string, Action*> Action::subscribedActions;
-{
-}
-
-Action::Action(const std::string &name)
- : ruleName(name), isChanged(false), type(SYNC), life(PERMANENT), plugin(nullptr), piAction(nullptr), stopOnErr(false), restriction(NONE), locked(false)
+Action::Action(const std::string &name, std::shared_ptr<PluginAction> pluginAction)
+ : ruleName(name), ignoreUndo(false), type(SYNC), life(PERMANENT), piAction(pluginAction),
+ locked(false), stopOnErr(false), subscribed(false), restriction(NONE)
{
}
Action::~Action()
{
- if (plugin)
- plugin->freeAction(piAction);
}
void Action::printInfo()
{
- DBG("Action(%s):ID(%s), Restrict(%d) piAction(%p)", getRuleName().c_str(), getID().c_str(), getRestrict(), piAction);
+ DBG("Action(%s):ID(%s), Restrict(%d)", getRuleName().c_str(), getID().c_str(), getRestrict());
}
void Action::setRuleName(const std::string &data)
return locked;
}
-void Action::setPlugin(Plugin *pi)
-{
- plugin = pi;
-}
-
void Action::setPrivilege(const std::string &val)
{
privilege = val;
observers.remove(obs);
}
-void Action::notifyObservers()
+std::string Action::backupUndoInfo()
{
- RET_IF(true == isChanged);
+ return piAction->getUndoInfo();
+}
+
+int Action::restoreUndoInfo(const std::string &info)
+{
+ int ret = piAction->setUndoInfo(info);
+ if (MODES_ERROR_NONE != ret) {
+ ignoreUndo = true;
+ ERR("piAction(%s) setUndoInfo(%s) Fail", piAction->getKey().c_str(), info.c_str());
+ return ret;
+ }
+ subscribeChanges();
+
+ return MODES_ERROR_NONE;
+}
+
+void Action::subscribeChanges()
+{
+ int ret = piAction->setChangedCallback(valueChangedCallback, this);
+ if (MODES_ERROR_NONE != ret) {
+ WARN("piAction(%s) setChangedCallback() Fail(%d)", piAction->getKey().c_str(), ret);
+ } else {
+ auto result = subscribedActions.insert(std::pair<std::string, Action*>(ruleName, this));
+ if (false == result.second)
+ WARN("Action(%s), already exists", ruleName.c_str());
+ subscribed = true;
+ }
+}
+void Action::unsubscribeChanges()
+{
+ if (!subscribed)
+ return;
+
+ subscribed = false;
piAction->unSetChangedCallback(valueChangedCallback, this);
- isChanged = true;
+ subscribedActions.erase(ruleName);
+}
- for (auto it = observers.begin(); it != observers.end(); ++it)
- (*it)->update(reinterpret_cast<int*>(this));
+void Action::invokeChangedCB()
+{
+ valueChangedCallback(subscribedActions[ruleName]);
}
void Action::valueChangedCallback(void *userData)
{
Action *action = (Action*)userData;
- RET_IF(NULL == action);
+ RET_IF(nullptr == action);
action->notifyObservers();
DBG("Action(%s) Changed", action->ruleName.c_str());
}
+
+void Action::notifyObservers()
+{
+ RET_IF(true == ignoreUndo);
+
+ unsubscribeChanges();
+ ignoreUndo = true;
+
+ for (auto it = observers.begin(); it != observers.end(); ++it)
+ (*it)->update(reinterpret_cast<int*>(this));
+}
*/
#pragma once
+#include <map>
#include <list>
#include <string>
+#include <memory>
#include "mdss.h"
-#include "Plugin.h"
#include "PluginAction.h"
#include "ActionObserver.h"
VOLATILE
} ActionRuleLife;
- Action();
- Action(const std::string &ruleName);
+ Action(const std::string &ruleName, std::shared_ptr<PluginAction> pluginAction);
virtual ~Action();
void printInfo();
ActionType getType();
void setLife(ActionRuleLife val);
ActionRuleLife getLife();
- void setPlugin(Plugin *pi);
void setPrivilege(const std::string &val);
std::string getPrivilege();
void attachObserver(ActionObserver *obs);
void detachObserver(ActionObserver *obs);
+ std::string backupUndoInfo();
+ int restoreUndoInfo(const std::string &info);
virtual int setValue(const std::string &val) = 0;
virtual std::string getStringOfValue() = 0;
virtual int apply() = 0;
virtual int applyOneShot() = 0;
virtual void undo() = 0;
- virtual int restoreUndoInfo(const std::string &info) = 0;
- virtual std::string backupUndoInfo() = 0;
protected:
- static void valueChangedCallback(void *userData);
+ void subscribeChanges();
+ void unsubscribeChanges();
+ void invokeChangedCB();
std::string ruleName;
- bool isChanged;
+ bool ignoreUndo;
ActionType type;
ActionRuleLife life;
- Plugin *plugin;
- PluginAction *piAction;
+ std::shared_ptr<PluginAction> piAction;
private:
+ static void valueChangedCallback(void *userData);
void notifyObservers();
std::string id;
std::string privilege;
+ bool locked; //Another action(same rule) is restricted(LOCK), It is assigned by ConflictManager
bool stopOnErr;
+ bool subscribed;
ActionRestrict restriction;
- bool locked; //Another action(same rule) is restricted(LOCK), It is assigned by ConflictManager
std::list<ActionObserver*> observers;
+ static std::map<std::string, Action*> subscribedActions;
};
MODES_NAMESPACE_END
#include <string>
#include "mdss.h"
+#include "Plugin.h"
#include "Action.h"
MODES_NAMESPACE_BEGIN
return undoDir;
}
-void ModeCareTaker::restoreMode(const Mode &mode)
+void ModeCareTaker::realPushMode(const Mode &mode)
{
savedModes.insert(std::pair<std::string, Mode>(mode.getName(), mode));
+
+ if (mode.hasEssential())
+ handleEssentialAction(mode);
}
void ModeCareTaker::pushMode(const Mode &mode)
{
- savedModes.insert(std::pair<std::string, Mode>(mode.getName(), mode));
-
- if (mode.hasEssential())
- handleEssentialAction(mode);
+ realPushMode(mode);
XMLGenerator gen;
gen.makeUndoInfoXML(undoDir + "/tizen_" + mode.getName() + MODES_UNDO_FILE_SUFFIX, mode);
~ModeCareTaker() = default;
std::string getUndoInfoDir();
- void restoreMode(const Mode &mode);
+ void realPushMode(const Mode &mode);
void pushMode(const Mode &mode);
int popMode(const std::string &name, Mode &mode);
bool isConflict(const Mode &mode);
Mode mode = parser->getMode();
undoInfoParser.putUndoInfo(mode);
- careTaker.restoreMode(mode);
+ careTaker.realPushMode(mode);
} catch (std::exception &e) {
ERR("parser(%s) Fail(%s)", fileFullPath.c_str(), e.what());
if (0 != remove(fileFullPath.c_str()))
int PluginMapper::loadPlugins()
{
DIR *dir;
- if ((dir = opendir(pluginDir.c_str())) == NULL) {
+ if ((dir = opendir(pluginDir.c_str())) == nullptr) {
ERR("opendir(%s) Fail(%d)", pluginDir.c_str(), errno);
throw ModesEx(ModesEx::SYSTEM_ERROR);
}
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) {
std::string file(entry->d_name);
- if (std::string::npos == file.find(MODES_PLUGIN_LIB_PREFIX)) //library validation
+ //library name validation check
+ if (std::string::npos == file.find(MODES_PLUGIN_LIB_PREFIX))
continue;
std::string fileFullPath = pluginDir + "/" + file;
}
/* load the symbols */
- create_t *create_object_func = (create_t *) dlsym(handle, "objectCreate");
- if (NULL == create_object_func) {
+ createFunc newPlugin = (createFunc)dlsym(handle, "objectCreate");
+ if (nullptr == newPlugin) {
ERR("dlsym(objectCreate) Fail(Plugin[%s] error[%s])", pluginFile.c_str(), dlerror());
dlclose(handle);
throw ModesEx(ModesEx::SYSTEM_ERROR);
}
/* create an instance of the class */
- Plugin *object = create_object_func();
- if (NULL == object) {
+ Plugin *object = newPlugin();
+ if (nullptr == object) {
ERR("create_object_func(%s) Fail", pluginFile.c_str());
dlclose(handle);
throw ModesEx(ModesEx::SYSTEM_ERROR);
int PluginMapper::unloadClass(const PluginPair &pluginPair)
{
void *handle = pluginPair.first;
- Plugin *object = pluginPair.second;
- std::string pluginName = object->getName();
+ Plugin *plugin = pluginPair.second;
+ std::string pluginName = plugin->getName();
- RETVM_IF(NULL == handle, MODES_ERROR_SYSTEM, "handle(%s) is null", pluginName.c_str());
+ RETVM_IF(nullptr == handle, MODES_ERROR_SYSTEM, "No handle(%s)", pluginName.c_str());
- destroy_t *delete_object_func = (destroy_t *)dlsym(handle, "objectDelete");
- if (NULL == delete_object_func) {
+ destroyFunc deletePlugin = (destroyFunc)dlsym(handle, "objectDelete");
+ if (nullptr == deletePlugin) {
ERR("dlsym(objectDelete) Fail(plugin[%s] error[%s])", pluginName.c_str(), dlerror());
dlclose(handle);
return MODES_ERROR_SYSTEM;
}
- delete_object_func(object);
+ deletePlugin(plugin);
dlclose(handle);
return MODES_ERROR_NONE;
(xmlChar*)"privilege",
};
-RuleManager::RuleManager(const std::string & actionRuleDir, const std::string &actionRuleXsd, const std::string &pluginDir)
+RuleManager::RuleManager(const std::string &actionRuleDir, const std::string &actionRuleXsd, const std::string &pluginDir)
: ruleDir(actionRuleDir), ruleXsd(actionRuleXsd), piMapper(pluginDir)
{
}
#pragma once
#include <map>
+#include <mutex>
#include <string>
#include <sstream>
#include <thread>
#include "mdss.h"
#include "Action.h"
+#include "ModesEx.h"
#include "ValueChecker.h"
MODES_NAMESPACE_BEGIN
template <typename T>
class TAction : public Action {
public:
- TAction(const std::string &name)
- : Action(name), undoing(false)
+ TAction(const std::string &name, std::shared_ptr<PluginAction> pluginAction)
+ : Action(name, pluginAction), undoing(false)
{
+ if (nullptr == pluginAction)
+ throw ModesEx(ModesEx::INVALID_ARG);
}
~TAction()
{
- if (undoing)
- undo();
-
- if (piAction)
- piAction->unSetChangedCallback(valueChangedCallback, this);
+ unsubscribeChanges();
}
void setValueAliases(const std::map<std::string, T> &list)
return MODES_ERROR_NONE;
}
- int restoreUndoInfo(const std::string &info) override
- {
- RETVM_IF(NULL == plugin, MODES_ERROR_NO_DATA, "Action(%s) : No plugin", ruleName.c_str());
-
- int pos = ruleName.find_first_of(".");
- piAction = plugin->getUndoAction(ruleName.substr(pos + 1), info);
- if (nullptr == piAction) {
- ERR("plugin(%s) getUndoAction() Fail", plugin->getName().c_str());
- return MODES_ERROR_NOT_SUPPORTED;
- }
- piAction->setChangedCallback(valueChangedCallback, this);
-
- return MODES_ERROR_NONE;
- }
-
- std::string backupUndoInfo() override
- {
- RETVM_IF(NULL == plugin, std::string(), "Action(%s) : No plugin", ruleName.c_str());
-
- if (nullptr == piAction) {
- DBG("No plugin Action(%s) for undo", ruleName.c_str());
- return std::string();
- }
-
- return plugin->serializeAction(piAction);
- }
-
int apply() override
{
- RETVM_IF(NULL == plugin, MODES_ERROR_NO_DATA, "Action(%s) : No plugin", ruleName.c_str());
+ std::lock_guard<std::mutex> lock(actionMutex);
- int pos = ruleName.find_first_of(".");
- PluginAction *tmpAction = nullptr;
- int ret = plugin->set(ruleName.substr(pos + 1), value, &tmpAction);
+ int ret = applySub();
if (MODES_ERROR_NONE != ret) {
- ERR("plugin(%s) set() Fail(%d)", plugin->getName().c_str(), ret);
+ ignoreUndo = true;
+ if (MODES_ERROR_ALREADY == ret)
+ return MODES_ERROR_NONE;
+ ERR("applySub(%s) Fail(%d)", ruleName.c_str(), ret);
return ret;
}
- if (tmpAction)
- tmpAction->setChangedCallback(valueChangedCallback, this);
- piAction = tmpAction;
+ subscribeChanges();
return MODES_ERROR_NONE;
}
int applyOneShot() override
{
- RETVM_IF(NULL == plugin, MODES_ERROR_NO_DATA, "Action(%s) : No plugin", ruleName.c_str());
+ std::lock_guard<std::mutex> lock(actionMutex);
- int pos = ruleName.find_first_of(".");
- PluginAction *tmpAction = nullptr;
- int ret = plugin->set(ruleName.substr(pos + 1), value, &tmpAction);
+ int ret = applySub();
if (MODES_ERROR_NONE != ret) {
- ERR("plugin(%s) set() Fail(%d)", plugin->getName().c_str(), ret);
- return ret;
+ ignoreUndo = true;
+ if (MODES_ERROR_ALREADY != ret) {
+ ERR("applySub(%s) Fail(%d)", ruleName.c_str(), ret);
+ return ret;
+ }
}
- piAction = tmpAction;
return MODES_ERROR_NONE;
}
void undo() override
{
- RETM_IF(NULL == plugin, "Action(%s) : No plugin", ruleName.c_str());
-
- //It control multithread condition
- if (Action::ActionType::ASYNC == type)
- undoing = true;
+ std::lock_guard<std::mutex> lock(actionMutex);
- RETM_IF(NULL == piAction, "Plugin(%s) : No piAction(%s)", plugin->getName().c_str(), ruleName.c_str());
-
- if (isChanged) {
+ if (ignoreUndo) {
INFO("Action(%s) : value changed", ruleName.c_str());
- plugin->freeAction(piAction);
} else {
- piAction->unSetChangedCallback(valueChangedCallback, this);
- plugin->undo(piAction); // piAction is deleted in undo()
+ unsubscribeChanges();
+ piAction->undo();
}
- piAction = nullptr;
}
private:
}
};
+ int applySub()
+ {
+ if (piAction->IsCurrentValue(value)) {
+ INFO("Action(%s) is Ignored because it is equal to current value", ruleName.c_str());
+ return MODES_ERROR_ALREADY;
+ }
+
+ invokeChangedCB();
+
+ int ret = piAction->set(value);
+ if (MODES_ERROR_NONE != ret) {
+ ERR("piAction(%s) set() Fail(%d)", piAction->getKey().c_str(), ret);
+ return ret;
+ }
+
+ return MODES_ERROR_NONE;
+ }
+
std::map<std::string, T, CaseIndependentLess> valueAliases;
+ std::mutex actionMutex;
bool undoing;
T value{};
};
#include <list>
#include <string>
#include <sstream>
+#include <functional>
#include "mdss.h"
#include "TAction.h"
#include "ActionRule.h"
Action* makeAction() override
{
- TAction<T> *action = new TAction<T>(ruleName);
- action->setValueAliases(valueAliasList);
- action->setPrivilege(privilege);
- action->setPlugin(plugin);
- action->setLife(life);
+ int pos = ruleName.find_first_of(".");
+ std::string actionKey = ruleName.substr(pos + 1);
+ std::shared_ptr<PluginAction> piAction(plugin->newAction(actionKey),
+ std::bind(&Plugin::deleteAction, plugin, std::placeholders::_1));
- return action;
+ try {
+ TAction<T> *action = new TAction<T>(ruleName, piAction);
+ action->setValueAliases(valueAliasList);
+ action->setPrivilege(privilege);
+ action->setLife(life);
+
+ return action;
+ } catch (ModesEx &e) {
+ ERR("makeAction() Fail(%s)", e.what());
+ }
+
+ return nullptr;
}
int addAlias(const std::string &alias, const std::string &value) override
void UndoInfoParser::parseInfo(xmlNodePtr node, const std::list<std::shared_ptr<Action>> &actionList)
{
char *ruleName = (char*)xmlGetProp(node, ModesXMLTag::RULE);
- if (ruleName == NULL) {
- ERR("rule attribute is null! [%s]", ModesXMLTag::RULE);
- throw ModesEx(ModesEx::PARSER_ERROR, "rule attribute is null!");
+ if (nullptr == ruleName) {
+ ERR("No value of (%s)", ModesXMLTag::RULE);
+ throw ModesEx(ModesEx::PARSER_ERROR, "No Rule Name");
}
- auto it = std::find_if_not(actionList.begin(), actionList.end(),
- [ruleName](std::shared_ptr<Action> a)->bool {return a->getRuleName().compare(ruleName);});
+ auto it = std::find_if(actionList.begin(), actionList.end(),
+ [&ruleName](std::shared_ptr<Action> a) {return (a->getRuleName() == ruleName);});
+
std::shared_ptr<Action> action = *it;
- if (action == nullptr) {
+ if (nullptr == action) {
ERR("Find Action(%s) Fail", ruleName);
xmlFree(ruleName);
- throw ModesEx(ModesEx::PARSER_ERROR, "Action is null!");
+ throw ModesEx(ModesEx::PARSER_ERROR, "No Action");
}
- xmlFree(ruleName);
char *nodeContent = (char*)xmlNodeGetContent(node);
- if (nodeContent == NULL)
- ERR("Node Content is null!");
+ if (nullptr == nodeContent)
+ ERR("No undo Info for Action(%s)", ruleName);
int ret = action->restoreUndoInfo(nodeContent ? nodeContent : "");
+ xmlFree(ruleName);
xmlFree(nodeContent);
-
if (MODES_ERROR_NONE != ret) {
ERR("Action(%s) setValue() Fail(%d)", action->getRuleName().c_str(), ret);
- throw ModesEx(ModesEx::PARSER_ERROR, "Invalid Action Value");
+ throw ModesEx(ModesEx::PARSER_ERROR, "Invalid UndoInfo");
}
action->printInfo();
EXPECT_FALSE(broker.emptyPluginMap());
Plugin *plugin = broker.piMapper.getPlugin("test");
- ASSERT_TRUE(plugin != NULL);
+ ASSERT_TRUE(plugin);
- ret = plugin->set("printInt", 0, nullptr);
+ PluginAction *piAction = plugin->newAction("printInt");
+ ret = piAction->set(0);
EXPECT_EQ(ret, MODES_ERROR_NONE);
- ret = plugin->set("printInt", false, nullptr);
+ ret = piAction->set(false);
EXPECT_EQ(ret, MODES_ERROR_NOT_SUPPORTED);
+ plugin->deleteAction(piAction);
- ret = plugin->set("printDouble", 1.234, nullptr);
+ piAction = plugin->newAction("printFloat");
+ ret = piAction->set(1.234);
EXPECT_EQ(ret, MODES_ERROR_NONE);
+ plugin->deleteAction(piAction);
- ret = plugin->set("printBool", false, nullptr);
+ piAction = plugin->newAction("printBool");
+ ret = piAction->set(false);
EXPECT_EQ(ret, MODES_ERROR_NONE);
- ret = plugin->set("printBool", 3, nullptr);
+ ret = piAction->set(3);
EXPECT_EQ(ret, MODES_ERROR_NOT_SUPPORTED);
+ plugin->deleteAction(piAction);
- ret = plugin->set("printString", string("String value"), nullptr);
+ piAction = plugin->newAction("printString");
+ ret = piAction->set(string("String value"));
EXPECT_EQ(ret, MODES_ERROR_NONE);
+ plugin->deleteAction(piAction);
+
+ piAction = plugin->newAction("alwaySameValue");
+ bool same = piAction->IsCurrentValue(string("String value"));
+ EXPECT_EQ(same, true);
+ ret = piAction->set(string("String value"));
+ EXPECT_EQ(ret, MODES_ERROR_NOT_SUPPORTED);
+ plugin->deleteAction(piAction);
ret = broker.piMapper.unloadPlugins();
EXPECT_EQ(ret, MODES_ERROR_NONE);