-/*
-$Revision: 1.44 $
-$Date: 2010/09/13 05:54:43 $
-$Author: faust $
-*/
-
-#ifndef USER_PROPERTY_H
-#define USER_PROPERTY_H
-
-#include <unistd.h> // access
+#pragma once
+
+#include "stg/user_conf.h"
+#include "stg/user_ips.h"
+#include "stg/store.h"
+#include "stg/admin.h"
+#include "stg/notifer.h"
+#include "stg/admin_conf.h"
+#include "stg/logger.h"
+#include "stg/locker.h"
+#include "stg/settings.h"
+#include "stg/scriptexecuter.h"
+#include "stg/common.h"
#include <ctime>
#include <string>
#include <set>
+#include <map>
#include <sstream>
#include <iostream>
+#include <mutex>
-#include "stg/logger.h"
-#include "stg/locker.h"
-#include "stg/scriptexecuter.h"
-
-#include "store.h"
-#include "admin.h"
-#include "notifer.h"
-#include "noncopyable.h"
+#include <unistd.h> // access
extern volatile time_t stgTime;
+namespace STG
+{
//-----------------------------------------------------------------------------
-template<typename varT>
-class USER_PROPERTY {
-public:
- USER_PROPERTY(varT & val);
- virtual ~USER_PROPERTY();
+struct UserPropertyBase {
+ virtual ~UserPropertyBase() = default;
+ virtual std::string ToString() const = 0;
+};
+//-----------------------------------------------------------------------------
+using Registry = std::map<std::string, UserPropertyBase*>;
+//-----------------------------------------------------------------------------
+template<typename T>
+class UserProperty : public UserPropertyBase {
+ public:
+ explicit UserProperty(T& val);
- void Set(const varT & rvalue);
+ void Set(const T& rhs);
+ T get() const { return value; }
- USER_PROPERTY<varT> & operator= (const varT & rvalue);
+ UserProperty<T>& operator=(const T& rhs);
- const varT * operator&() const throw() { return &value; }
- const varT & ConstData() const throw() { return value; }
+ const T* operator&() const noexcept { return &value; }
+ const T& ConstData() const noexcept { return value; }
- operator const varT&() const throw() { return value; }
+ operator const T&() const noexcept { return value; }
- void AddBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
- void DelBeforeNotifier(const PROPERTY_NOTIFIER_BASE<varT> * n);
+ void AddBeforeNotifier(PropertyNotifierBase<T>* n);
+ void DelBeforeNotifier(const PropertyNotifierBase<T>* n);
- void AddAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
- void DelAfterNotifier(const PROPERTY_NOTIFIER_BASE<varT> * n);
+ void AddAfterNotifier(PropertyNotifierBase<T>* n);
+ void DelAfterNotifier(const PropertyNotifierBase<T>* n);
- time_t ModificationTime() const throw() { return modificationTime; }
- void ModifyTime() throw();
+ time_t ModificationTime() const noexcept { return modificationTime; }
+ void ModifyTime() noexcept;
-private:
- varT & value;
- time_t modificationTime;
- std::set<PROPERTY_NOTIFIER_BASE<varT> *> beforeNotifiers;
- std::set<PROPERTY_NOTIFIER_BASE<varT> *> afterNotifiers;
- pthread_mutex_t mutex;
+ std::string ToString() const override;
+ private:
+ T& value;
+ time_t modificationTime;
+ std::set<PropertyNotifierBase<T>*> beforeNotifiers;
+ std::set<PropertyNotifierBase<T>*> afterNotifiers;
+ std::mutex mutex;
};
//-----------------------------------------------------------------------------
-template<typename varT>
-class USER_PROPERTY_LOGGED: public USER_PROPERTY<varT> {
-public:
- USER_PROPERTY_LOGGED(varT & val,
- const std::string & n,
- bool isPassword,
- bool isStat,
- STG_LOGGER & logger,
- const std::string & sd);
- virtual ~USER_PROPERTY_LOGGED() {}
-
- USER_PROPERTY_LOGGED<varT> * GetPointer() throw() { return this; }
- const varT & Get() const { return USER_PROPERTY<varT>::ConstData(); }
- const std::string & GetName() const { return name; }
- bool Set(const varT & val,
- const ADMIN * admin,
- const std::string & login,
- const STORE * store,
- const std::string & msg = "");
-private:
- void WriteAccessDenied(const std::string & login,
- const ADMIN * admin,
- const std::string & parameter);
-
- void WriteSuccessChange(const std::string & login,
- const ADMIN * admin,
- const std::string & parameter,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & msg,
- const STORE * store);
-
- void OnChange(const std::string & login,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const ADMIN * admin);
-
- STG_LOGGER & stgLogger;
- bool isPassword;
- bool isStat;
- std::string name;
- const std::string scriptsDir;
+template<typename T>
+class UserPropertyLogged: public UserProperty<T> {
+ public:
+ UserPropertyLogged(T& val,
+ const std::string& n,
+ bool isPassword,
+ bool isStat,
+ const Settings& s,
+ Registry& properties);
+
+ UserPropertyLogged<T>* GetPointer() noexcept { return this; }
+ const UserPropertyLogged<T>* GetPointer() const noexcept { return this; }
+ const T& Get() const { return UserProperty<T>::ConstData(); }
+ const std::string& GetName() const { return name; }
+ bool Set(const T& val,
+ const Admin& admin,
+ const std::string& login,
+ const Store& store,
+ const std::string& msg = "");
+ private:
+ void WriteAccessDenied(const std::string& login,
+ const Admin& admin,
+ const std::string& parameter);
+
+ void WriteSuccessChange(const std::string& login,
+ const Admin& admin,
+ const std::string& parameter,
+ const std::string& oldValue,
+ const std::string& newValue,
+ const std::string& msg,
+ const Store& store);
+
+ void OnChange(const std::string& login,
+ const std::string& paramName,
+ const std::string& oldValue,
+ const std::string& newValue,
+ const Admin& admin);
+
+ Logger& stgLogger;
+ bool isPassword;
+ bool isStat;
+ std::string name;
+ const Settings& settings;
};
//-----------------------------------------------------------------------------
-class USER_PROPERTIES : private NONCOPYABLE {
-/*
- В этом месте важен порядок следования приватной и открытой частей.
- Это связано с тем, что часть которая находится в публичной секции
- по сути является завуалированной ссылкой на закрытую часть. Т.о. нам нужно
- чтобы конструкторы из закрытой части вызвались раньше открытой. Поэтомому в
- начале идет закрытая секция
- * */
-
-private:
- USER_STAT stat;
- USER_CONF conf;
-
-public:
- USER_PROPERTIES(const std::string & sd);
-
- USER_STAT & Stat() { return stat; }
- USER_CONF & Conf() { return conf; }
- const USER_STAT & GetStat() const { return stat; }
- const USER_CONF & GetConf() const { return conf; }
- void SetStat(const USER_STAT & s) { stat = s; }
- void SetConf(const USER_CONF & c) { conf = c; }
-
- void SetProperties(const USER_PROPERTIES & p) { stat = p.stat; conf = p.conf; }
-
- USER_PROPERTY_LOGGED<double> cash;
- USER_PROPERTY_LOGGED<DIR_TRAFF> up;
- USER_PROPERTY_LOGGED<DIR_TRAFF> down;
- USER_PROPERTY_LOGGED<double> lastCashAdd;
- USER_PROPERTY_LOGGED<time_t> passiveTime;
- USER_PROPERTY_LOGGED<time_t> lastCashAddTime;
- USER_PROPERTY_LOGGED<double> freeMb;
- USER_PROPERTY_LOGGED<time_t> lastActivityTime;
-
- USER_PROPERTY_LOGGED<std::string> password;
- USER_PROPERTY_LOGGED<int> passive;
- USER_PROPERTY_LOGGED<int> disabled;
- USER_PROPERTY_LOGGED<int> disabledDetailStat;
- USER_PROPERTY_LOGGED<int> alwaysOnline;
- USER_PROPERTY_LOGGED<std::string> tariffName;
- USER_PROPERTY_LOGGED<std::string> nextTariff;
- USER_PROPERTY_LOGGED<std::string> address;
- USER_PROPERTY_LOGGED<std::string> note;
- USER_PROPERTY_LOGGED<std::string> group;
- USER_PROPERTY_LOGGED<std::string> email;
- USER_PROPERTY_LOGGED<std::string> phone;
- USER_PROPERTY_LOGGED<std::string> realName;
- USER_PROPERTY_LOGGED<double> credit;
- USER_PROPERTY_LOGGED<time_t> creditExpire;
- USER_PROPERTY_LOGGED<USER_IPS> ips;
- USER_PROPERTY_LOGGED<std::string> userdata0;
- USER_PROPERTY_LOGGED<std::string> userdata1;
- USER_PROPERTY_LOGGED<std::string> userdata2;
- USER_PROPERTY_LOGGED<std::string> userdata3;
- USER_PROPERTY_LOGGED<std::string> userdata4;
- USER_PROPERTY_LOGGED<std::string> userdata5;
- USER_PROPERTY_LOGGED<std::string> userdata6;
- USER_PROPERTY_LOGGED<std::string> userdata7;
- USER_PROPERTY_LOGGED<std::string> userdata8;
- USER_PROPERTY_LOGGED<std::string> userdata9;
+class UserProperties {
+ /*
+ В этом месте важен порядок следования приватной и открытой частей.
+ Это связано с тем, что часть которая находится в публичной секции
+ по сути является завуалированной ссылкой на закрытую часть. Т.о. нам нужно
+ чтобы конструкторы из закрытой части вызвались раньше открытой. Поэтомому в
+ начале идет закрытая секция
+ * */
+
+ private:
+ UserStat stat;
+ UserConf conf;
+
+ Registry properties;
+ public:
+ explicit UserProperties(const Settings& s);
+
+ UserStat& Stat() { return stat; }
+ UserConf& Conf() { return conf; }
+ const UserStat& GetStat() const { return stat; }
+ const UserConf& GetConf() const { return conf; }
+ void SetStat(const UserStat& s) { stat = s; }
+ void SetConf(const UserConf& c) { conf = c; }
+
+ void SetProperties(const UserProperties& p) { stat = p.stat; conf = p.conf; }
+
+ std::string GetPropertyValue(const std::string & name) const;
+ bool Exists(const std::string & name) const;
+
+ UserPropertyLogged<double> cash;
+ UserPropertyLogged<DirTraff> up;
+ UserPropertyLogged<DirTraff> down;
+ UserPropertyLogged<double> lastCashAdd;
+ UserPropertyLogged<time_t> passiveTime;
+ UserPropertyLogged<time_t> lastCashAddTime;
+ UserPropertyLogged<double> freeMb;
+ UserPropertyLogged<time_t> lastActivityTime;
+
+ UserPropertyLogged<std::string> password;
+ UserPropertyLogged<int> passive;
+ UserPropertyLogged<int> disabled;
+ UserPropertyLogged<int> disabledDetailStat;
+ UserPropertyLogged<int> alwaysOnline;
+ UserPropertyLogged<std::string> tariffName;
+ UserPropertyLogged<std::string> nextTariff;
+ UserPropertyLogged<std::string> address;
+ UserPropertyLogged<std::string> note;
+ UserPropertyLogged<std::string> group;
+ UserPropertyLogged<std::string> email;
+ UserPropertyLogged<std::string> phone;
+ UserPropertyLogged<std::string> realName;
+ UserPropertyLogged<double> credit;
+ UserPropertyLogged<time_t> creditExpire;
+ UserPropertyLogged<UserIPs> ips;
+ UserPropertyLogged<std::string> userdata0;
+ UserPropertyLogged<std::string> userdata1;
+ UserPropertyLogged<std::string> userdata2;
+ UserPropertyLogged<std::string> userdata3;
+ UserPropertyLogged<std::string> userdata4;
+ UserPropertyLogged<std::string> userdata5;
+ UserPropertyLogged<std::string> userdata6;
+ UserPropertyLogged<std::string> userdata7;
+ UserPropertyLogged<std::string> userdata8;
+ UserPropertyLogged<std::string> userdata9;
};
//=============================================================================
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-USER_PROPERTY<varT>::USER_PROPERTY(varT & val)
+UserProperty<T>::UserProperty(T& val)
: value(val),
modificationTime(stgTime),
beforeNotifiers(),
- afterNotifiers(),
- mutex()
-{
-pthread_mutex_init(&mutex, NULL);
-}
-//-----------------------------------------------------------------------------
-template <typename varT>
-inline
-USER_PROPERTY<varT>::~USER_PROPERTY()
+ afterNotifiers()
{
-pthread_mutex_destroy(&mutex);
}
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-void USER_PROPERTY<varT>::ModifyTime() throw()
+void UserProperty<T>::ModifyTime() noexcept
{
-modificationTime = stgTime;
+ modificationTime = stgTime;
}
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-void USER_PROPERTY<varT>::Set(const varT & rvalue)
+void UserProperty<T>::Set(const T& rvalue)
{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
+ std::lock_guard<std::mutex> lock(mutex);
-typename std::set<PROPERTY_NOTIFIER_BASE<varT> *>::iterator ni;
+ T oldVal = value;
-varT oldVal = value;
+ auto ni = beforeNotifiers.begin();
+ while (ni != beforeNotifiers.end())
+ (*ni++)->Notify(oldVal, rvalue);
-ni = beforeNotifiers.begin();
-while (ni != beforeNotifiers.end())
- (*ni++)->Notify(oldVal, rvalue);
+ value = rvalue;
+ modificationTime = stgTime;
-value = rvalue;
-modificationTime = stgTime;
-
-ni = afterNotifiers.begin();
-while (ni != afterNotifiers.end())
- (*ni++)->Notify(oldVal, rvalue);
+ ni = afterNotifiers.begin();
+ while (ni != afterNotifiers.end())
+ (*ni++)->Notify(oldVal, rvalue);
}
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-USER_PROPERTY<varT> & USER_PROPERTY<varT>::operator= (const varT & newValue)
+UserProperty<T>& UserProperty<T>::operator=(const T& newValue)
{
-Set(newValue);
-return *this;
+ Set(newValue);
+ return *this;
}
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-void USER_PROPERTY<varT>::AddBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
+void UserProperty<T>::AddBeforeNotifier(PropertyNotifierBase<T>* n)
{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-beforeNotifiers.insert(n);
+ std::lock_guard<std::mutex> lock(mutex);
+ beforeNotifiers.insert(n);
}
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-void USER_PROPERTY<varT>::DelBeforeNotifier(const PROPERTY_NOTIFIER_BASE<varT> * n)
+void UserProperty<T>::DelBeforeNotifier(const PropertyNotifierBase<T>* n)
{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-beforeNotifiers.erase(const_cast<PROPERTY_NOTIFIER_BASE<varT> *>(n));
+ std::lock_guard<std::mutex> lock(mutex);
+ beforeNotifiers.erase(const_cast<PropertyNotifierBase<T>*>(n));
}
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-void USER_PROPERTY<varT>::AddAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
+void UserProperty<T>::AddAfterNotifier(PropertyNotifierBase<T>* n)
{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-afterNotifiers.insert(n);
+ std::lock_guard<std::mutex> lock(mutex);
+ afterNotifiers.insert(n);
}
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-void USER_PROPERTY<varT>::DelAfterNotifier(const PROPERTY_NOTIFIER_BASE<varT> * n)
+void UserProperty<T>::DelAfterNotifier(const PropertyNotifierBase<T>* n)
{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-afterNotifiers.erase(const_cast<PROPERTY_NOTIFIER_BASE<varT> *>(n));
+ std::lock_guard<std::mutex> lock(mutex);
+ afterNotifiers.erase(const_cast<PropertyNotifierBase<T>*>(n));
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-USER_PROPERTY_LOGGED<varT>::USER_PROPERTY_LOGGED(varT & val,
- const std::string & n,
- bool isPass,
- bool isSt,
- STG_LOGGER & logger,
- const std::string & sd)
-
- : USER_PROPERTY<varT>(val),
- stgLogger(logger),
+UserPropertyLogged<T>::UserPropertyLogged(T& val,
+ const std::string& n,
+ bool isPass,
+ bool isSt,
+ const Settings& s,
+ Registry& properties)
+
+ : UserProperty<T>(val),
+ stgLogger(Logger::get()),
isPassword(isPass),
isStat(isSt),
name(n),
- scriptsDir(sd)
+ settings(s)
{
+ properties.insert(std::make_pair(ToLower(name), this));
}
//-------------------------------------------------------------------------
-template <typename varT>
-bool USER_PROPERTY_LOGGED<varT>::Set(const varT & val,
- const ADMIN * admin,
- const std::string & login,
- const STORE * store,
- const std::string & msg)
+template <typename T>
+inline
+bool UserPropertyLogged<T>::Set(const T& val,
+ const Admin& admin,
+ const std::string& login,
+ const Store& store,
+ const std::string& msg)
{
-const PRIV * priv = admin->GetPriv();
+ const auto priv = admin.GetPriv();
-if ((priv->userConf && !isStat) ||
- (priv->userStat && isStat) ||
- (priv->userPasswd && isPassword) ||
- (priv->userCash && name == "cash"))
+ if ((priv->userConf && !isStat) ||
+ (priv->userStat && isStat) ||
+ (priv->userPasswd && isPassword) ||
+ (priv->userCash && name == "cash"))
{
- std::stringstream oldVal;
- std::stringstream newVal;
+ std::stringstream oldVal;
+ std::stringstream newVal;
- oldVal.flags(oldVal.flags() | std::ios::fixed);
- newVal.flags(newVal.flags() | std::ios::fixed);
+ oldVal.flags(oldVal.flags() | std::ios::fixed);
+ newVal.flags(newVal.flags() | std::ios::fixed);
- oldVal << USER_PROPERTY<varT>::ConstData();
- newVal << val;
+ oldVal << UserProperty<T>::ConstData();
+ newVal << val;
- OnChange(login, name, oldVal.str(), newVal.str(), admin);
+ OnChange(login, name, oldVal.str(), newVal.str(), admin);
- if (isPassword)
- {
- WriteSuccessChange(login, admin, name, "******", "******", msg, store);
- }
- else
- {
- WriteSuccessChange(login, admin, name, oldVal.str(), newVal.str(), msg, store);
- }
- USER_PROPERTY<varT>::Set(val);
- return true;
+ if (isPassword)
+ WriteSuccessChange(login, admin, name, "******", "******", msg, store);
+ else
+ WriteSuccessChange(login, admin, name, oldVal.str(), newVal.str(), msg, store);
+
+ UserProperty<T>::Set(val);
+ return true;
}
-else
- {
+
WriteAccessDenied(login, admin, name);
return false;
- }
-return true;
}
//-------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-void USER_PROPERTY_LOGGED<varT>::WriteAccessDenied(const std::string & login,
- const ADMIN * admin,
- const std::string & parameter)
+void UserPropertyLogged<T>::WriteAccessDenied(const std::string& login,
+ const Admin& admin,
+ const std::string& parameter)
{
-stgLogger("%s Change user \'%s.\' Parameter \'%s\'. Access denied.",
- admin->GetLogStr().c_str(), login.c_str(), parameter.c_str());
+ stgLogger("%s Change user \'%s.\' Parameter \'%s\'. Access denied.",
+ admin.GetLogStr().c_str(), login.c_str(), parameter.c_str());
}
//-------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
inline
-void USER_PROPERTY_LOGGED<varT>::WriteSuccessChange(const std::string & login,
- const ADMIN * admin,
- const std::string & parameter,
- const std::string & oldValue,
- const std::string & newValue,
- const std::string & msg,
- const STORE * store)
+void UserPropertyLogged<T>::WriteSuccessChange(const std::string& login,
+ const Admin& admin,
+ const std::string& parameter,
+ const std::string& oldValue,
+ const std::string& newValue,
+ const std::string& msg,
+ const Store& store)
{
-stgLogger("%s User \'%s\': \'%s\' parameter changed from \'%s\' to \'%s\'. %s",
- admin->GetLogStr().c_str(),
- login.c_str(),
- parameter.c_str(),
- oldValue.c_str(),
- newValue.c_str(),
- msg.c_str());
-
-store->WriteUserChgLog(login, admin->GetLogin(), admin->GetIP(), parameter, oldValue, newValue, msg);
+ stgLogger("%s User \'%s\': \'%s\' parameter changed from \'%s\' to \'%s\'. %s",
+ admin.GetLogStr().c_str(),
+ login.c_str(),
+ parameter.c_str(),
+ oldValue.c_str(),
+ newValue.c_str(),
+ msg.c_str());
+
+ for (size_t i = 0; i < settings.GetFilterParamsLog().size(); ++i)
+ if (settings.GetFilterParamsLog()[i] == "*" || strcasecmp(settings.GetFilterParamsLog()[i].c_str(), parameter.c_str()) == 0)
+ {
+ store.WriteUserChgLog(login, admin.GetLogin(), admin.GetIP(), parameter, oldValue, newValue, msg);
+ return;
+ }
}
//-------------------------------------------------------------------------
-template <typename varT>
-void USER_PROPERTY_LOGGED<varT>::OnChange(const std::string & login,
- const std::string & paramName,
- const std::string & oldValue,
- const std::string & newValue,
- const ADMIN * admin)
+template <typename T>
+void UserPropertyLogged<T>::OnChange(const std::string& login,
+ const std::string& paramName,
+ const std::string& oldValue,
+ const std::string& newValue,
+ const Admin& admin)
{
-std::string filePath = scriptsDir + "/OnChange";
+ const auto filePath = settings.GetScriptsDir() + "/OnChange";
-if (access(filePath.c_str(), X_OK) == 0)
- {
- std::string execString("\"" + filePath + "\" \"" + login + "\" \"" + paramName + "\" \"" + oldValue + "\" \"" + newValue + "\" \"" + admin->GetLogin() + "\" \"" + admin->GetIPStr() + "\"");
- ScriptExec(execString.c_str());
- }
-else
+ if (access(filePath.c_str(), X_OK) == 0)
{
- stgLogger("Script OnChange cannot be executed. File %s not found.", filePath.c_str());
+ const auto execString = "\"" + filePath + "\" \"" + login + "\" \"" + paramName + "\" \"" + oldValue + "\" \"" + newValue + "\" \"" + admin.GetLogin() + "\" \"" + admin.GetIPStr() + "\"";
+ ScriptExec(execString.c_str());
}
+ else
+ stgLogger("Script OnChange cannot be executed. File %s not found.", filePath.c_str());
+}
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+//-------------------------------------------------------------------------
+inline
+std::string UserProperties::GetPropertyValue(const std::string& name) const
+{
+ const auto it = properties.find(ToLower(name));
+ if (it == properties.end())
+ return "";
+ return it->second->ToString();
+}
+//-----------------------------------------------------------------------------
+inline
+bool UserProperties::Exists(const std::string& name) const
+{
+ return properties.find(ToLower(name)) != properties.end();
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
-template<typename varT>
+template<typename T>
inline
-std::ostream & operator<< (std::ostream & stream, const USER_PROPERTY<varT> & value)
+std::ostream& operator<<(std::ostream& stream, const UserProperty<T>& value)
{
-return stream << value.ConstData();
+ return stream << value.ConstData();
}
//-----------------------------------------------------------------------------
+template<typename T>
+inline
+std::string UserProperty<T>::ToString() const
+{
+ std::ostringstream stream;
+ stream << value;
+ return stream.str();
+}
-#endif // USER_PROPERTY_H
+}