Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/libraries/core/class/IdentifierManager.cc @ 10518

Last change on this file since 10518 was 10518, checked in by landauf, 9 years ago

load modules AFTER core was initialized. load each module with a separate ModuleInstance. unloading is not yet implemented…

  • Property svn:eol-style set to native
File size: 11.4 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file
31    @brief Implementation of the Identifier class.
32*/
33
34#include "IdentifierManager.h"
35
36#include <ostream>
37
38#include "util/StringUtils.h"
39#include "core/Core.h"
40#include "core/config/ConfigValueContainer.h"
41#include "core/XMLPort.h"
42#include "core/object/ClassFactory.h"
43
44namespace orxonox
45{
46    /* static */ IdentifierManager& IdentifierManager::getInstance()
47    {
48        static IdentifierManager instance;
49        return instance;
50    }
51
52    IdentifierManager::IdentifierManager()
53    {
54        this->hierarchyCreatingCounter_s = 0;
55        this->recordTraceForIdentifier_ = NULL;
56    }
57
58    /**
59     * Registers the identifier in all maps of the IdentifierManager.
60     */
61    void IdentifierManager::addIdentifier(Identifier* identifier)
62    {
63        orxout(verbose, context::identifier) << "Adding identifier for " << identifier->getName() << " / " << identifier->getTypeInfo().name() << endl;
64
65        this->identifiers_.insert(identifier);
66        this->identifierByString_[identifier->getName()] = identifier;
67        this->identifierByLowercaseString_[getLowercase(identifier->getName())] = identifier;
68        this->identifierByNetworkId_[identifier->getNetworkID()] = identifier;
69    }
70
71    /**
72     * Unregisters the identifier from all maps of the IdentifierManager.
73     */
74    void IdentifierManager::removeIdentifier(Identifier* identifier)
75    {
76        this->identifiers_.erase(identifier);
77        this->identifierByString_.erase(identifier->getName());
78        this->identifierByLowercaseString_.erase(getLowercase(identifier->getName()));
79        this->identifierByNetworkId_.erase(identifier->getNetworkID());
80    }
81
82    /**
83        @brief Creates the class-hierarchy by creating and destroying one object of each type.
84    */
85    void IdentifierManager::createClassHierarchy()
86    {
87        orxout(internal_status) << "Create class-hierarchy" << endl;
88        this->startCreatingHierarchy();
89
90        std::set<Identifier*> initializedIdentifiers;
91
92        // ensure root context exists before starting to create objects. if the root context is dynamically created while creating the class hierarchy, we
93        // would mistakenly assume the class of the currently created object inherits from Context
94        Context::getRootContext();
95
96        // iterate over all identifiers, create one instance of each class and initialize the identifiers
97        {
98            Context temporaryContext(NULL);
99            for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
100            {
101                Identifier* identifier = (*it);
102                if (identifier->isInitialized())
103                    continue;
104
105                orxout(verbose, context::identifier) << "Initialize ClassIdentifier<" << identifier->getName() << ">-Singleton." << endl;
106                // To initialize the identifier, we create a new object and delete it afterwards.
107                if (identifier->hasFactory())
108                {
109                    this->identifierTraceOfNewObject_.clear();
110                    this->recordTraceForIdentifier_ = identifier;
111
112                    Identifiable* temp = identifier->fabricate(&temporaryContext);
113
114                    this->recordTraceForIdentifier_ = NULL;
115
116                    if (temp->getIdentifier() != identifier)
117                        orxout(internal_error) << "Newly created object of type " << identifier->getName() << " has unexpected identifier. Did you forget to use RegisterObject(classname)?" << endl;
118
119                    identifier->initializeParents(this->identifierTraceOfNewObject_[temp]);
120
121                    delete temp;
122                }
123
124                initializedIdentifiers.insert(identifier);
125            }
126
127            size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
128            if (numberOfObjects > 0)
129                orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
130        }
131
132        // finish the initialization of all identifiers
133        for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
134        {
135            Identifier* identifier = (*it);
136
137            if (initializedIdentifiers.find(identifier) != initializedIdentifiers.end())
138                identifier->finishInitialization();
139            else if (!identifier->isInitialized())
140                orxout(internal_error) << "Identifier was registered late and is not initialized: " << identifier->getName() << " / " << identifier->getTypeInfo().name() << endl;
141        }
142
143        // only check class hierarchy in dev mode because it's an expensive operation and it requires a developer to fix detected problems anyway.
144        if (!Core::exists() || Core::getInstance().getConfig()->inDevMode())
145            this->verifyClassHierarchy();
146
147        this->stopCreatingHierarchy();
148        orxout(internal_status) << "Finished class-hierarchy creation" << endl;
149    }
150
151    /**
152     * Verifies if the class hierarchy is consistent with the RTTI.
153     */
154    void IdentifierManager::verifyClassHierarchy()
155    {
156        Context temporaryContext(NULL);
157        for (std::set<Identifier*>::const_iterator it1 = this->identifiers_.begin(); it1 != this->identifiers_.end(); ++it1)
158        {
159            if (!(*it1)->hasFactory())
160                continue;
161
162            Identifiable* temp = (*it1)->fabricate(&temporaryContext);
163
164            for (std::set<Identifier*>::const_iterator it2 = this->identifiers_.begin(); it2 != this->identifiers_.end(); ++it2)
165            {
166                bool isA_AccordingToRtti = (*it2)->canDynamicCastObjectToIdentifierClass(temp);
167                bool isA_AccordingToClassHierarchy = temp->isA((*it2));
168
169                if (isA_AccordingToRtti != isA_AccordingToClassHierarchy)
170                {
171                    orxout(internal_error) << "Class hierarchy does not match RTTI: Class hierarchy claims that " << (*it1)->getName() <<
172                        (isA_AccordingToClassHierarchy ? " is a " : " is not a ") << (*it2)->getName() << " but RTTI says the opposite." << endl;
173                }
174            }
175
176            delete temp;
177        }
178        orxout(internal_info) << "Class hierarchy matches RTTI" << endl;
179
180        size_t numberOfObjects = temporaryContext.getObjectList<Listable>()->size();
181        if (numberOfObjects > 0)
182            orxout(internal_warning) << "There are still " << numberOfObjects << " listables left after creating the class hierarchy" << endl;
183    }
184
185    /**
186     * @brief Resets all Identifiers.
187     */
188    void IdentifierManager::destroyClassHierarchy()
189    {
190        orxout(internal_status) << "Destroy class-hierarchy" << endl;
191        for (std::set<Identifier*>::const_iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
192            (*it)->reset();
193    }
194
195    /**
196     * @brief Notifies the IdentifierManager about a newly created object while creating the class hierarchy.
197     */
198    void IdentifierManager::createdObject(Identifiable* identifiable)
199    {
200        if (this->isCreatingHierarchy())
201        {
202            if (this->recordTraceForIdentifier_)
203            {
204                std::list<const Identifier*>& traceForObject = this->identifierTraceOfNewObject_[identifiable];
205                if (std::find(traceForObject.begin(), traceForObject.end(), identifiable->getIdentifier()) != traceForObject.end())
206                {
207                    orxout(internal_warning) << this->recordTraceForIdentifier_->getName() << " inherits two times from " <<
208                        identifiable->getIdentifier()->getName() << ". Did you forget to use virtual inheritance?" << endl;
209                }
210                traceForObject.push_back(identifiable->getIdentifier());
211            }
212        }
213        else
214            orxout(internal_warning) << "createdObject() called outside of class hierarchy creation" << endl;
215    }
216
217    /**
218        @brief Returns the Identifier with a given name.
219        @param name The name of the wanted Identifier
220        @return The Identifier
221    */
222    Identifier* IdentifierManager::getIdentifierByString(const std::string& name)
223    {
224        std::map<std::string, Identifier*>::const_iterator it = this->identifierByString_.find(name);
225        if (it != this->identifierByString_.end())
226            return it->second;
227        else
228            return 0;
229    }
230
231    /**
232        @brief Returns the Identifier with a given name in lowercase.
233        @param name The name of the wanted Identifier
234        @return The Identifier
235    */
236    Identifier* IdentifierManager::getIdentifierByLowercaseString(const std::string& name)
237    {
238        std::map<std::string, Identifier*>::const_iterator it = this->identifierByLowercaseString_.find(name);
239        if (it != this->identifierByLowercaseString_.end())
240            return it->second;
241        else
242            return 0;
243    }
244
245    /**
246        @brief Returns the Identifier with a given network ID.
247        @param id The network ID of the wanted Identifier
248        @return The Identifier
249    */
250    Identifier* IdentifierManager::getIdentifierByID(const uint32_t id)
251    {
252        std::map<uint32_t, Identifier*>::const_iterator it = this->identifierByNetworkId_.find(id);
253        if (it != this->identifierByNetworkId_.end())
254            return it->second;
255        else
256            return 0;
257    }
258
259    /**
260        @brief Returns the Identifier with a given typeid-name.
261        @param name The typeid-name of the wanted Identifier
262        @return The Identifier
263    */
264    Identifier* IdentifierManager::getIdentifierByTypeInfo(const std::type_info& typeInfo)
265    {
266        // TODO: use std::type_index and a map to find identifiers by type_info (only with c++11)
267        for (std::set<Identifier*>::iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
268            if ((*it)->getTypeInfo() == typeInfo)
269                return (*it);
270        return 0;
271    }
272
273    /**
274        @brief Cleans the NetworkID map (needed on clients for correct initialization)
275    */
276    void IdentifierManager::clearNetworkIDs()
277    {
278        this->identifierByNetworkId_.clear();
279    }
280
281    /**
282        @brief Destroys all Identifiers. Called when exiting the program.
283    */
284    void IdentifierManager::destroyAllIdentifiers()
285    {
286        for (std::set<Identifier*>::iterator it = this->identifiers_.begin(); it != this->identifiers_.end(); ++it)
287            delete (*it);
288
289        this->identifiers_.clear();
290        this->identifierByString_.clear();
291        this->identifierByLowercaseString_.clear();
292        this->identifierByNetworkId_.clear();
293    }
294}
Note: See TracBrowser for help on using the repository browser.