1 /* Copyright (C) 2000-2006 Thomas Bopp, Thorsten Hampel, Ludger Merkens
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * $Id: factory.pike,v 1.2 2009/08/07 15:22:36 nicke Exp $
19 inherit "/classes/Object";
23 #include <attributes.h>
29 #include <exception.h>
30 //! This is the factory class - other factories are derived from this one.
31 //! See the factory pattern for factories in general.
32 //! A factory is used by calling the execute() function and passing a mapping
33 //! of params. Each factory used the param "name" for execution in order to
34 //! give a new object a name. The factory for a class is retrieved by calling
35 //! the globally available function "get_factory(int classbit)", for example
36 //! get_factory(CLASS_USER).
37 class factory : public Object{
47 Thread.Queue updateQueue = Thread.Queue();
48 mapping mRegAttributes =([ ]); // "attribute-name":Attribute
49 mapping mUpdAttributes=([ ]);
52 bool check_swap() { return false; }
53 bool check_upgrade() { return false; }
57 * Init callback function sets a data storage.
66 add_data_storage(STORE_ATTREG, retrieve_attr_registration,
67 restore_attr_registration);
73 register_class_attribute(UserAttribute(OBJ_NAME, "object name", CMD_TYPE_STRING,""));
74 register_class_attribute(UserAttribute(OBJ_DESC, "description", CMD_TYPE_STRING,""));
75 register_class_attribute(UserAttribute(OBJ_ICON, "icon", CMD_TYPE_OBJECT, 0));
76 register_class_attribute(UserAttribute(OBJ_LINK_ICON,"link icon",CMD_TYPE_OBJECT,0));
77 register_class_attribute(Attribute(OBJ_URL,"url", CMD_TYPE_STRING, 0,
78 get_module("filepath:url")));
79 register_class_attribute(UserAttribute(OBJ_KEYWORDS,"keywords",CMD_TYPE_ARRAY,({})));
80 register_class_attribute
81 (PositionAttribute(OBJ_POSITION_X, "x-position", CMD_TYPE_FLOAT, 0.0));
82 register_class_attribute
83 (PositionAttribute(OBJ_POSITION_Y, "y-position", CMD_TYPE_FLOAT, 0.0));
84 register_class_attribute
85 (PositionAttribute(OBJ_POSITION_Z, "z-position", CMD_TYPE_FLOAT, 0.0));
86 register_class_attribute
87 (PositionAttribute(OBJ_WIDTH, "width of object", CMD_TYPE_FLOAT, 0.0));
88 register_class_attribute
89 (PositionAttribute(OBJ_HEIGHT, "height of object", CMD_TYPE_FLOAT, 0.0));
91 register_class_attribute(UserAttribute(OBJ_LANGUAGE,"language",CMD_TYPE_STRING,"de"));
92 register_class_attribute(Attribute(OBJ_ANNO_MESSAGE_IDS,
93 "maps message ids to annotations",
97 CONTROL_ATTR_SERVER));
98 register_class_attribute(Attribute(OBJ_ANNO_MISSING_IDS,
99 "stores message ids which were missing for annotations",
103 CONTROL_ATTR_SERVER));
104 register_class_attribute(Attribute(OBJ_ONTHOLOGY,
105 "Onthology of the object.",
111 register_class_attribute(Attribute(OBJ_VERSIONOF,
112 "points to the current version",
115 register_class_attribute(Attribute(OBJ_LINKS,
116 "all links of this object",
119 register_class_attribute(Attribute(OBJ_PATH,
120 "the path of this object",
128 * A factory calls initialization of factory when it is loaded.
134 if ( !mappingp(mRegAttributes) )
135 mRegAttributes = ([]);
136 mUpdAttributes = ([ ]);
138 if ( sizeof(mUpdAttributes) > 0 ) {
139 MESSAGE("Updating Instances after loading factory !");
140 update_instances(mUpdAttributes);
143 mUpdAttributes = ([ ]);
149 * Object constructor. Here the Attribute registration mapping is initialized.
155 mRegAttributes = ([]);
157 require_save(STORE_ATTREG);
163 * See if a given name is valid for objects created by this factory.
165 * @param string name - the name of the object
167 void valid_name(string name)
169 if ( !stringp(name) )
170 steam_user_error("The name of an object must be a string !");
171 if ( search(name, "/") >= 0 )
172 steam_user_error("/ is not allowed in Object Names...(%O)", name);
173 if ( !xml.utf8_check(name) )
174 steam_user_error("Name %O of object is not utf-8 !", name);
179 * create a new object of 'doc_class'
181 * @param string name - the name of the new object
182 * @param string doc_class - the class of the new object
183 * @param object env - the env the object should be moved to
184 * @param mapping|int attr - attribute mapping for initial attribute settings
185 * @param void|mapping attrAcq - acquired attributes
186 * @param void|mapping attrLocked - locked attributes initialization
187 * @param void|mapping sanction - sanction initialization
188 * @param void|mapping sanctionMeta - meta sanction initialization
189 * @return pointer to the new object
193 object_create(string name, string doc_class, object env, int|mapping attr,
194 void|mapping attrAcq, void|mapping attrLocked,
195 void|mapping sanction, void|mapping sanctionMeta)
199 user = geteuid() || this_user();
201 doc_class = CLASS_PATH + doc_class + ".pike";
202 SECURITY_LOG("New object of class:" + doc_class + " at " + ctime(time()));
206 if ( mappingp(attr) ) {
207 foreach(values(attr), mixed v) {
208 if ( stringp(v) && !xml.utf8_check(v) )
209 error("Create: Invalid Attribute found (utf-8 check failed).");
213 if ( objectp(env) && !(env->get_object_class() & CLASS_CONTAINER) )
214 steam_error("Failed to move object to " + env->get_object_id() +
215 " : object is no container !");
217 obj = new(doc_class, name, attr);
219 THROW("Failed to create object !", E_ERROR);
221 function obj_set_attribute = obj->get_function("do_set_attribute");
222 function obj_acquire_attribute = obj->get_function("do_set_acquire_attribute");
223 function obj_lock_attribute = obj->get_function("do_lock_attribute");
224 function obj_sanction_object = obj->get_function("do_sanction_object");
225 function obj_sanction_object_meta =obj->get_function("do_sanction_object_meta");
228 obj_acquire_attribute);
230 if ( !stringp(name) || name == "" )
231 THROW("No name set for object !", E_ERROR);
233 obj_set_attribute(OBJ_NAME, name);
234 obj_set_attribute(OBJ_CREATION_TIME, time());
236 if ( !mappingp(attr) || !objectp(attr[OBJ_ICON]) )
237 obj_acquire_attribute(OBJ_ICON, _Server->get_module("icons"));
239 if ( !stringp(obj->query_attribute(OBJ_NAME)) ||
240 obj->query_attribute(OBJ_NAME) == "" )
241 THROW("Strange error - attribute name setting failed !", E_ERROR);
243 SECURITY_LOG("Object " + obj->get_object_id() + " name set on " +
246 if ( !objectp(user) )
247 user = MODULE_USERS->lookup("root");
248 obj->set_creator(user);
250 if ( user != MODULE_USERS->lookup("root") &&
251 user != MODULE_USERS->lookup("guest") )
253 obj_sanction_object(user, SANCTION_ALL);
254 obj_sanction_object_meta(user, SANCTION_ALL);
256 obj->set_acquire(obj->get_environment);
257 ASSERTINFO(obj->get_acquire() == obj->get_environment,
258 "Acquire not on environment, huh?");
260 foreach(indices(attrAcq||([])), string acqi) {
261 obj_acquire_attribute(acqi, attrAcq[acqi]);
263 foreach(indices(attrLocked||([])), string locki) {
264 obj_lock_attribute(locki);
266 foreach(indices(sanction||([])), object sanctioni) {
267 if ( objectp(sanctioni) )
268 obj_sanction_object(sanctioni, sanction[sanctioni]);
270 foreach(indices(sanctionMeta||([])), object sanctionmi) {
271 if ( objectp(sanctionmi) )
272 obj_sanction_object_meta(sanctionmi, sanctionMeta[sanctionmi]);
277 if ( objectp(env) ) {
284 bool install_attribute(Attribute attr,
287 void|function obj_set_attribute,
288 void|function obj_acquire_attribute)
290 if ( !objectp(obj) || obj->status() < 0 )
293 if ( !functionp(obj_set_attribute) )
294 obj_set_attribute = obj->get_function("do_set_attribute");
295 if ( !functionp(obj_acquire_attribute))
296 obj_acquire_attribute = obj->get_function("do_set_acquire_attribute");
299 mixed key = attr->get_key();
300 mixed def = attr->get_default_value();
301 string|object acq = attr->get_acquire();
303 if ( obj->is_locked(key) )
306 if ( !zero_type(def) ) {
307 obj_set_attribute(key, copy_value(def));
310 // do not acquire attributes for the default objects set
311 if ( !objectp(acq) || acq != obj )
314 obj_acquire_attribute(key, obj->find_function(acq));
316 obj_acquire_attribute(key, acq);
318 if ( !zero_type(val) ) {
319 obj_set_attribute(key, val);
323 FATAL("Error registering attribute: %s\n%s",
325 describe_backtrace(err[1]));
330 array get_inherited_factories()
332 array factories = _Server->get_factories();
333 array depFactories = ({ });
334 array myPrograms = Program.all_inherits(object_program(this_object()));
335 foreach ( factories, object factory ) {
336 if ( search(myPrograms, object_program(factory->get_object())) >= 0 ) {
337 depFactories += ({ factory });
343 array get_derived_factories()
345 array factories = _Server->get_factories();
346 array depFactories = ({ });
347 foreach ( factories, object factory ) {
348 array facPrograms = Program.all_inherits(object_program(factory->get_object()));
349 if ( search(facPrograms, object_program(this_object())) >= 0 ) {
350 depFactories += ({ factory });
357 * register all attributes for an object
359 * @param obj - the object to register attributes
360 * @see register_class_attribute
363 void install_attributes(object obj,
366 void|function obj_set_attribute,
367 void|function obj_acquire_attribute)
371 if ( !functionp(obj_set_attribute) )
372 obj_set_attribute = obj->get_function("do_set_attribute");
373 if ( !functionp(obj_acquire_attribute) )
374 obj_acquire_attribute = obj->get_function("do_set_acquire_attribute");
376 if ( !mappingp(mAttr) )
379 if ( stringp(key) ) {
380 attr = mRegAttributes[key];
383 obj_acquire_attribute);
386 foreach (indices(mRegAttributes), key) {
387 attr = mRegAttributes[key];
389 obj_acquire_attribute);
397 * register attributes for the class(es) this factory creates.
398 * each newly created object will have the attributes registered here.
400 * @param Attribute attr - the new attribute to register.
401 * @param void|function conversion - conversion function for all objects
403 * @see classes/Object.set_attribute
404 * @see libraries/Attributes.pmod.Attribute
407 register_attribute(Attribute attr, void|object conversion)
409 try_event(EVENT_REGISTER_ATTRIBUTE, CALLER, attr);
411 if ( register_class_attribute(attr, conversion) == 0 )
414 // register on all dependent factories too
415 array factories = values(_Server->get_classes());
416 foreach ( factories, object factory ) {
417 factory = factory->get_object();
418 if ( factory->get_object_id() == get_object_id() )
420 if ( search(Program.all_inherits(object_program(factory)),
421 object_program(this_object())) >= 0 )
422 factory->register_attribute(copy_value(attr), conversion);
425 update_instances(attr->get_key());
427 run_event(EVENT_REGISTER_ATTRIBUTE, CALLER, attr);
430 void unregister_attribute(string key)
432 Attribute attr = mRegAttributes[key];
433 if ( !objectp(attr) )
436 try_event(EVENT_REGISTER_ATTRIBUTE, CALLER, attr);
437 if ( unregister_class_attribute(attr) == 0 )
439 array factories = values(_Server->get_classes());
440 foreach ( factories, object factory ) {
441 factory = factory->get_object();
442 if ( factory->get_object_id() == get_object_id() )
444 if ( search(Program.all_inherits(object_program(factory)),
445 object_program(this_object())) >= 0 )
446 factory->unregister_attribute(copy_value(attr));
449 run_event(EVENT_REGISTER_ATTRIBUTE, CALLER, attr);
453 * Update instances of objects created by this factory when a new
454 * attribute is registered. This sets the new default value for the attribute
455 * and the basic acquiring.
457 * @param mixed key - the attribute key.
458 * @param function|void conv - the conversion function.
460 void update_instances(mixed key)
463 if ( !mappingp(key) ) {
464 attr = mRegAttributes[key];
465 if ( !objectp(attr) )
466 THROW("Unregistered Attribute !", E_ERROR);
469 if ( sizeof(key) == 0 ) {
470 MESSAGE("(%s) Nothing to update !", get_identifier());
475 array instances = get_all_objects();
477 int csz = sizeof(instances);
478 foreach(instances, object instance) {
480 if ( cnt % 10000 == 0 ) {
481 MESSAGE("Registering attribute %O : %d of %d objects done.",
484 if ( !objectp(instance) || instance->status() < 0 )
488 // object is saved and can be updated later !
489 if ( instance->status() == PSTAT_DISK )
492 // this should not happen anymore!!!
493 if ( !functionp(instance->get_object_class) ||
494 !(instance->get_object_class() & get_class_id()) ) {
495 FATAL("Got wrong instance %O in %s\n", instance, get_identifier());
498 if ( mappingp(key) ) {
499 function obj_set_attribute = instance->get_function("do_set_attribute");
500 function obj_acquire_attribute = instance->get_function("do_set_acquire_attribute");
501 foreach( indices(key), mixed k) {
502 attr = mRegAttributes[k];
503 if ( !attr->check_convert(instance) &&
504 !check_attribute_registration(instance, attr) )
505 install_attribute(attr, instance, UNDEFINED,
507 obj_acquire_attribute);
511 if ( !attr->check_convert(instance) &&
512 !check_attribute_registration(instance, attr) ) {
513 install_attribute(attr, instance);
521 * Register_class_attribute is called by register_attribute,
522 * this function is local and does no security checks. All instances
523 * of this class are set to the default value and acquiring settings.
525 * @param Attribute attr - the Attribute to register for this factories class
526 * @see register_attribute
529 int register_class_attribute(Attribute attr, void|object conv)
531 string|int key = attr->get_key();
532 Attribute pattr = mRegAttributes[key];
538 do_set_attribute(FACTORY_LAST_REGISTER, time());
540 attr->set_converter(conv);
541 mRegAttributes[key] = attr;
542 require_save(STORE_ATTREG);
546 foreach( get_inherited_factories(), object factory ) {
547 if ( factory->is_attribute(key) )
551 mUpdAttributes[key] = 1;
558 int unregister_class_attribute(Attribute attr)
560 m_delete(mRegAttributes, attr->get_key());
561 require_save(STORE_ATTREG);
569 * Init an attribute of this class calls registration function.
571 * @see register_class_attribute
576 init_class_attribute(mixed key, int type, string desc,
577 int event_read, int event_write,
578 object|int acq, int cntrl, mixed def)
580 Attribute attr = Attribute(key, desc, type, def, acq,
581 cntrl, event_read, event_write);
582 if ( !objectp(mRegAttributes[key]) )
583 register_class_attribute(attr);
589 * Check if an attributes value is going to be set correctly.
590 * An objects set_attribute function calls this check and
591 * throws an error if the value is incorrect.
593 * @param mixed key - the attributes key.
594 * @param mixed data - the new value of the attribute.
595 * @param int|void regType - registration data to check, if void use factories.
596 * @return true or false.
598 bool check_attribute(mixed key, mixed data, int|void regType)
600 object caller = CALLER;
602 if ( !objectp(mRegAttributes[key]) )
605 // see if our factory has something about this attribute
606 // if previous attribute in zero
607 // this will end up in loop when installing attributes
608 if ( zero_type(caller->query_attribute(key)) )
609 install_attributes(CALLER, ([ ]), key);
612 // value 0 should be ok
613 if ( data == 0 ) return true;
614 if ( key == "OBJ_NAME" )
617 return mRegAttributes[key]->check_attribute(data);
622 * check the registration of an attribute
624 * @param object obj - the object to check the attribute
625 * @param Attribute attr - the new registered attribute
626 * @return if the attribute is ok
628 bool check_attribute_registration(object obj, Attribute attr)
630 string key = attr->get_key();
631 mixed val = obj->query_attribute(key);
632 if ( zero_type(val) )
635 if ( val == attr->get_default_value() )
637 switch(attr->get_type()) {
638 case CMD_TYPE_INT: if ( !intp(val) ) return false; break;
639 case CMD_TYPE_FLOAT: if ( !floatp(val) ) return false; break;
640 case CMD_TYPE_STRING: if ( !stringp(val) ) return false; break;
641 case CMD_TYPE_OBJECT: if ( !objectp(val) ) return false; break;
642 case CMD_TYPE_ARRAY: if ( !arrayp(val) ) return false; break;
643 case CMD_TYPE_MAPPING: if ( !mappingp(val) ) return false; break;
644 case CMD_TYPE_PROGRAM: if ( !programp(val) ) return false; break;
645 case CMD_TYPE_FUNCTION: if ( !functionp(val) ) return false; break;
651 * check all attributes of an object
653 * @param object obj - the object to check
654 * @return true or false (attributes changed)
655 * @see check_attribute
657 bool check_attributes(object obj)
659 int last_change = obj->query_attribute(OBJ_LAST_CHANGED);
660 if ( last_change <= do_query_attribute(FACTORY_LAST_REGISTER) ) {
662 if ( modeRegister ) {
663 FATAL("checking object %O while registering .... !\n", obj);
664 steam_error("registration failed due to loading objects ...");
666 function obj_set_attribute=obj->get_function("do_set_attribute");
667 function obj_acquire_attribute=obj->get_function("do_set_acquire_attribute");
669 foreach ( indices(mRegAttributes), string key ) {
670 Attribute a = mRegAttributes[key];
671 if ( !a->check_convert(obj) &&
672 !check_attribute_registration(obj, a) )
673 install_attribute(a, obj, UNDEFINED,
675 obj_acquire_attribute);
678 obj_set_attribute(OBJ_LAST_CHANGED, time());
686 * Get the registration information for one attribute of this class.
688 * @param mixed key the attributes key.
689 * @return The array of registered data.
691 Attribute describe_attribute(mixed key)
693 return copy_value(mRegAttributes[key]);
697 * Get all registered attributes for this class.
699 * @return the mapping of registered attributes for this class
700 * @see register_class_attribute
702 mapping get_attributes()
704 return copy_value(mRegAttributes);
707 bool is_attribute(string key)
709 if ( mRegAttributes[key] )
715 * Get the event to fire upon reading the attribute.
717 * @param mixed key - the attributes key.
718 * @return read event or zero.
719 * @see get_attribute_change_event
721 int get_attributes_read_event(mixed key)
723 if ( !arrayp(mRegAttributes[key]) )
725 return mRegAttributes[key]->get_read_event();
729 * Get the event to fire upon changing an attribute.
731 * @param mixed key - the attributes key.
732 * @return change event or zero.
733 * @see get_attributes_read_event
735 int get_attributes_change_event(mixed key)
737 if ( !mappingp(mRegAttributes) || !objectp(mRegAttributes[key]) )
738 return EVENT_ATTRIBUTES_CHANGE;
739 return mRegAttributes[key]->get_write_event();
743 * Get an attributes default value and acquiring.
745 * @param mixed key - the attributes key.
746 * @return array of default value and acquiring setting.
748 array get_attribute_default(mixed key)
750 return ({ mRegAttributes[key]->get_default_value(),
751 mRegAttributes[key]->get_acquire() });
755 * Called by the _Database to get the registered attributes (saved data)
758 * @return mapping of registered attributes.
762 retrieve_attr_registration()
764 if ( CALLER != _Database )
765 THROW("Invalid call to retrieve_data()", E_ACCESS);
767 "RegAttributes":map(mRegAttributes, save_attribute),
774 mapping save_attribute(Attribute attr)
782 * Called by _Database to restore the registered attributes data.
784 * @param mixed data - restore data.
788 restore_attr_registration(mixed data)
790 if ( CALLER != _Database )
791 THROW("Invalid call to restore_data()", E_ACCESS);
792 foreach(indices(data->RegAttributes), mixed key) {
795 mixed v = data->RegAttributes[key];
798 if ( intp(acq) && acq == 1 )
799 acq = REG_ACQ_ENVIRONMENT;
800 Attribute a = Attribute(key,v[1],v[0],v[6],acq,v[5],v[2],v[3]);
801 mRegAttributes[key] = a;
804 Attribute a = Attribute(v->key,v->desc,v->type,v->def,v->acquire,
805 v->control, v->event_read, v->event_write);
807 a->set_converter(v->converter);
808 mRegAttributes[key] = a;
815 array get_all_objects()
817 return _Database->get_objects_by_class("/classes/"+get_class_name());
820 string get_identifier() { return "factory"; }
821 int get_object_class() { return ::get_object_class() | CLASS_FACTORY; }
822 string get_class_name() { return "undefined"; }
823 int get_class_id() { return CLASS_OBJECT; }