00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include "autoconfig.h"
00034 #endif
00035
00036 #include "uuid/uuid.h"
00037 #include "session_manager.h"
00038 #include "config_manager.h"
00039 #include "tools.h"
00040 #include "tools.h"
00041 #include "timer.h"
00042
00043 #define UI_UPDATE_ID_HASH_SIZE 61
00044 #define MAX_UI_UPDATE_IDS 10
00045
00046 using namespace zmm;
00047 using namespace mxml;
00048
00049 SINGLETON_MUTEX(SessionManager, false);
00050
00051 Session::Session(long timeout) : Dictionary_r()
00052 {
00053 this->timeout = timeout;
00054 loggedIn = false;
00055 sessionID = nil;
00056 uiUpdateIDs = Ref<DBRHash<int> >(new DBRHash<int>(UI_UPDATE_ID_HASH_SIZE, MAX_UI_UPDATE_IDS + 5, INVALID_OBJECT_ID, INVALID_OBJECT_ID_2));
00057 updateAll = false;
00058 access();
00059 }
00060
00061 void Session::containerChangedUI(int objectID)
00062 {
00063 if (objectID == INVALID_OBJECT_ID)
00064 return;
00065 if (! updateAll)
00066 {
00067 AUTOLOCK(mutex);
00068 if (! updateAll)
00069 {
00070 if (uiUpdateIDs->size() >= MAX_UI_UPDATE_IDS)
00071 {
00072 updateAll = true;
00073 uiUpdateIDs->clear();
00074 }
00075 else
00076 uiUpdateIDs->put(objectID);
00077 }
00078 }
00079 }
00080
00081 void Session::containerChangedUI(Ref<IntArray> objectIDs)
00082 {
00083 if (updateAll)
00084 return;
00085 if (objectIDs == nil)
00086 return;
00087 int arSize = objectIDs->size();
00088 AUTOLOCK(mutex);
00089 if (updateAll)
00090 return;
00091 if (uiUpdateIDs->size() + arSize >= MAX_UI_UPDATE_IDS)
00092 {
00093 updateAll = true;
00094 uiUpdateIDs->clear();
00095 return;
00096 }
00097 for (int i = 0; i < arSize; i++)
00098 {
00099 uiUpdateIDs->put(objectIDs->get(i));
00100 }
00101 }
00102
00103 String Session::getUIUpdateIDs()
00104 {
00105 if (! hasUIUpdateIDs())
00106 return nil;
00107 AUTOLOCK(mutex);
00108 if (updateAll)
00109 {
00110 updateAll = false;
00111 return _("all");
00112 }
00113 hash_data_array_t<int> hash_data_array;
00114 uiUpdateIDs->getAll(&hash_data_array);
00115 String ret = intArrayToCSV(hash_data_array.data, hash_data_array.size);
00116 if (ret != nil)
00117 uiUpdateIDs->clear();
00118 return ret;
00119 }
00120
00121 bool Session::hasUIUpdateIDs()
00122 {
00123 if (updateAll)
00124 return true;
00125
00126 return (uiUpdateIDs->size() > 0);
00127 }
00128
00129 void Session::clearUpdateIDs()
00130 {
00131 log_debug("clearing UI updateIDs\n");
00132 AUTOLOCK(mutex);
00133 uiUpdateIDs->clear();
00134 updateAll = false;
00135 }
00136
00137 SessionManager::SessionManager() : TimerSubscriberSingleton<SessionManager>()
00138 {
00139 Ref<ConfigManager> configManager = ConfigManager::getInstance();
00140
00141 accounts = configManager->getDictionaryOption(CFG_SERVER_UI_ACCOUNT_LIST);
00142 sessions = Ref<Array<Session> >(new Array<Session>());
00143 timerAdded = false;
00144 }
00145
00146 Ref<Session> SessionManager::createSession(long timeout)
00147 {
00148 Ref<Session> newSession(new Session(timeout));
00149 AUTOLOCK(mutex);
00150
00151 int count=0;
00152 String sessionID;
00153 do
00154 {
00155 sessionID = generate_random_id();
00156 if (count++ > 100)
00157 throw _Exception(_("There seems to be something wrong with the random numbers. I tried to get a unique id 100 times and failed. last sessionID: ") + sessionID);
00158 }
00159 while(getSession(sessionID, false) != nil);
00160
00161 newSession->setID(sessionID);
00162 sessions->append(newSession);
00163 checkTimer();
00164 return newSession;
00165 }
00166
00167 Ref<Session> SessionManager::getSession(String sessionID, bool doLock)
00168 {
00169 AUTOLOCK_NOLOCK(mutex)
00170 if (doLock)
00171 AUTORELOCK();
00172 for (int i = 0; i < sessions->size(); i++)
00173 {
00174 Ref<Session> s = sessions->get(i);
00175 if (s->getID() == sessionID)
00176 return s;
00177 }
00178 return nil;
00179 }
00180
00181 void SessionManager::removeSession(String sessionID)
00182 {
00183 AUTOLOCK(mutex);
00184 for (int i = 0; i < sessions->size(); i++)
00185 {
00186 Ref<Session> s = sessions->get(i);
00187 if (s->getID() == sessionID)
00188 {
00189 sessions->remove(i);
00190 checkTimer();
00191 i--;
00192 return;
00193 }
00194 }
00195 }
00196
00197 String SessionManager::getUserPassword(String user)
00198 {
00199 if (accounts == nil)
00200 {
00201 return nil;
00202 }
00203 return accounts->get(user);
00204 }
00205
00206 void SessionManager::containerChangedUI(int objectID)
00207 {
00208 if (sessions->size() <= 0)
00209 return;
00210 AUTOLOCK(mutex);
00211 int sesSize = sessions->size();
00212 for (int i = 0; i < sesSize; i++)
00213 {
00214 Ref<Session> session = sessions->get(i);
00215 if (session->isLoggedIn())
00216 session->containerChangedUI(objectID);
00217 }
00218 }
00219
00220 void SessionManager::containerChangedUI(Ref<IntArray> objectIDs)
00221 {
00222 if (sessions->size() <= 0)
00223 return;
00224 AUTOLOCK(mutex);
00225 int sesSize = sessions->size();
00226 for (int i = 0; i < sesSize; i++)
00227 {
00228 Ref<Session> session = sessions->get(i);
00229 if (session->isLoggedIn())
00230 session->containerChangedUI(objectIDs);
00231 }
00232 }
00233
00234 void SessionManager::checkTimer()
00235 {
00236 if (sessions->size() > 0 && ! timerAdded)
00237 {
00238 Timer::getInstance()->addTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this), SESSION_TIMEOUT_CHECK_INTERVAL);
00239 timerAdded = true;
00240 }
00241 else if (sessions->size() <= 0 && timerAdded)
00242 {
00243 Timer::getInstance()->removeTimerSubscriber(AS_TIMER_SUBSCRIBER_SINGLETON(this));
00244 timerAdded = false;
00245 }
00246 }
00247
00248 void SessionManager::timerNotify(Ref<Object> parameter)
00249 {
00250 log_debug("notified... %d sessions.\n", sessions->size());
00251 AUTOLOCK(mutex);
00252 struct timespec now;
00253 getTimespecNow(&now);
00254 for (int i = 0; i < sessions->size(); i++)
00255 {
00256 Ref<Session> session = sessions->get(i);
00257 if (getDeltaMillis(session->getLastAccessTime(), &now) > 1000 * session->getTimeout())
00258 {
00259 log_debug("session timeout: %s - diff: %ld\n", session->getID().c_str(), getDeltaMillis(session->getLastAccessTime(), &now));
00260 sessions->remove(i);
00261 checkTimer();
00262 i--;
00263 }
00264 }
00265 }