]> git.stg.codes - stg.git/blobdiff - include/stg/user_property.h
Fix build on Darwin.
[stg.git] / include / stg / user_property.h
index ade21f4e8024e040dd2d6d13ba393e02e27e8731..d73a636b2df42b82ae0296f395dfd6ef4caac6d4 100644 (file)
-/*
-$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/subscriptions.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 "store.h"
-#include "admin.h"
-#include "notifer.h"
-#include "logger.h"
-#include "locker.h"
-#include "scriptexecuter.h"
-#include "noncopyable.h"
-
-extern const volatile time_t stgTime;
+#include <unistd.h> // access
 
+namespace STG
+{
 //-----------------------------------------------------------------------------
-template<typename varT>
-class USER_PROPERTY {
-public:
-    USER_PROPERTY(varT & val);
-    virtual ~USER_PROPERTY();
-
-    void Set(const varT & rvalue);
+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);
 
-    USER_PROPERTY<varT> & operator= (const varT & rvalue);
+        void Set(const T& rhs);
+        T get() const { return value; }
 
-    const varT * operator&() const throw() { return &value; }
-    const varT & ConstData() const throw() { return value; }
+        UserProperty<T>& operator=(const T& rhs);
 
-    operator const varT&() const throw() { return value; }
+        const T* operator&() const noexcept { return &value; }
+        const T& ConstData() const noexcept { return value; }
 
-    void    AddBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
-    void    DelBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
+        operator const T&() const noexcept { return value; }
 
-    void    AddAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
-    void    DelAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n);
+        template <typename F>
+        auto beforeChange(F&& f) { return m_beforeCallbacks.add(std::forward<F>(f)); }
+        template <typename F>
+        auto afterChange(F&& f) { return m_afterCallbacks.add(std::forward<F>(f)); }
 
-    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;
+        Subscriptions<T, T> m_beforeCallbacks;
+        Subscriptions<T, T> m_afterCallbacks;
+        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)
+      modificationTime(time(NULL))
 {
-pthread_mutex_init(&mutex, NULL);
 }
 //-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
 inline
-USER_PROPERTY<varT>::~USER_PROPERTY()
+void UserProperty<T>::ModifyTime() noexcept
 {
-pthread_mutex_destroy(&mutex);
+    modificationTime = time(NULL);
 }
 //-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
 inline
-void USER_PROPERTY<varT>::ModifyTime() throw()
+void UserProperty<T>::Set(const T& rhs)
 {
-modificationTime = stgTime;
-}
-//-----------------------------------------------------------------------------
-template <typename varT>
-inline
-void USER_PROPERTY<varT>::Set(const varT & rvalue)
-{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-
-typename std::set<PROPERTY_NOTIFIER_BASE<varT> *>::iterator ni;
+    std::lock_guard<std::mutex> lock(mutex);
 
-varT oldVal = value;
+    T oldVal = value;
 
-ni = beforeNotifiers.begin();
-while (ni != beforeNotifiers.end())
-    (*ni++)->Notify(oldVal, rvalue);
+    m_beforeCallbacks.notify(oldVal, rhs);
 
-value = rvalue;
-modificationTime = stgTime;
+    value = rhs;
+    modificationTime = time(NULL);
 
-ni = afterNotifiers.begin();
-while (ni != afterNotifiers.end())
-    (*ni++)->Notify(oldVal, rvalue);
-}
-//-----------------------------------------------------------------------------
-template <typename varT>
-inline
-USER_PROPERTY<varT> & USER_PROPERTY<varT>::operator= (const varT & newValue)
-{
-Set(newValue);
-return *this;
+    m_afterCallbacks.notify(oldVal, rhs);
 }
 //-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
 inline
-void USER_PROPERTY<varT>::AddBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
+UserProperty<T>& UserProperty<T>::operator=(const T& newValue)
 {
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-beforeNotifiers.insert(n);
+    Set(newValue);
+    return *this;
 }
 //-----------------------------------------------------------------------------
-template <typename varT>
-inline
-void USER_PROPERTY<varT>::DelBeforeNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
-{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-beforeNotifiers.erase(n);
-}
 //-----------------------------------------------------------------------------
-template <typename varT>
-inline
-void USER_PROPERTY<varT>::AddAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
-{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-afterNotifiers.insert(n);
-}
 //-----------------------------------------------------------------------------
-template <typename varT>
+template <typename T>
 inline
-void USER_PROPERTY<varT>::DelAfterNotifier(PROPERTY_NOTIFIER_BASE<varT> * n)
-{
-STG_LOCKER locker(&mutex, __FILE__, __LINE__);
-afterNotifiers.erase(n);
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-template <typename varT>
-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();
-std::string adm_login = admin->GetLogin();
-std::string adm_ip = admin->GetIPStr();
-
-if ((priv->userConf && !isStat) ||
-    (priv->userStat && isStat) ||
-    (priv->userPasswd && isPassword) ||
-    (priv->userCash && name == "cash"))
+    const auto& priv = admin.priv();
+
+    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() | ios::fixed);
-    newVal.flags(newVal.flags() | 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.logStr().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.logStr().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.login(), admin.IP(), 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.login() + "\" \"" + admin.IPStr() + "\"";
+        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
-ostream & operator<< (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
+}