Chapter 21: Customization Classes

 

Customizing Overview

C++/VERSANT mechanisms are redefined with methods on PCustomizeFundamental, VSession. See also the init() method on PVirtual.

Redefinable Mechanisms

The following C++/VERSANT mechanisms can be redefined.

Create object

new Persistent Type()

O_NEW_PERSISTENT(Type)()

new (PClassObject) Type()

make_copy()

Read object

->()

locateobj()

Write object

dirty()

preptochange()

Delete object

delete

deleteobj()

Set data type

Internal operation

Activate object

Internal operation

 
You might want to redefine these mechanisms to perform additional work or to handle special situations in which you are mixing interface languages or creating classes at run time.

These mechanisms can be redefined because they operate through relay methods. The relay methods are defined in the PCustomizeFundamental and VSession classes, and their behavior can be altered with other methods in PCustomizeFundamental and VSession.

By default, the above C++/VERSANT mechanisms that create, read, write, and delete objects are relayed to the following C/VERSANT functions:

Create object

o_makeobj()

Read object

o_locateobj()

Write object

o_preptochange()

Delete object

o_deleteobj()

 
By default, the mechanisms that activate objects use C++ instructions specific to your compiler.

•    Note — The words "locator" and "activator" are consistently misspelled as "locater" and "activater" in PCustomizeFundamental and VSession methods.

Redefining Default Behavior

To override default behavior for the redefinable C++/VERSANT mechanisms, do the following.

1.  Create new functions that create, read, write, delete, and/or activate objects.

Your replacement functions must have the same arguments, return values, and C bindings as the default C/VERSANT functions.

Typically, you will use the default functions and add additional code that performs the tasks you desire.

2.  Redefine the relay methods using your new functions.

After a session has begun, use methods in PCustomizeFundamental and VSession to redefine the relay methods that create, read, write, delete, and activate objects.

PHandle Usage Notes

Some customization methods use the data type PHandle.

The PHandle type is typedef as LinkAny.

You can use PHandle as you would LinkAny. However, to delete it, you must use deleteobj(), rather than operator delete.

Example: Fixing a Class

The following subroutine illustrates how to fix a class. The function defined can be used in place of o_locateobj() and activateWSlots() calls.

After calling o_makeobj(), o_createobj(), or make_object(), instead of calling o_locateobj() and PClassObject<CheatClass>.activateWSlots(), call this function. It will do the work of both, plus fix an address in an internal header properly.

Pass to this function the o_object link returned from o_makeobj(). It will return the top of the object, just as o_locateobj() does.

In the following, you can substitute proper error handling for the assert() function.

void*
fix_and_locate_new_object( o_object obj )
{
   PResult pr;
   void* top= ((PHandle)obj)->getObject(pr, RLOCK);
   assert ( pr.is_ok() );
   return top;
}

Following is a reference to the relay methods on PCustomizeFundamental and VSession that redefine default behavior.

 

PCustomizeFundamental

 

get_call_user_init_flag()

static o_4b get_call_user_init_flag(PDOM *dom) const;

Return the current status of the flag used in set_call_user_init_flag() in PCustomizeFundamental.

If this method returns 1, then objects will be initialized with the init() method when they are brought into memory. If this method returns 0, then init() will not be called.

See also:

init() in PVirtual

set_call_user_init_flag()

 

get_makeobj_thrower()

static vpp_makeobj_thrower_t *get_makeobj_thrower(PDOM *dom) const;

Get the currently defined object creation exception handler.

See also:

set_makeobj_thrower()

set_object_maker()

 

get_object_activater()

static vpp_object_activater_t *get_object_activater(PDOM *dom) const;

Get the object activation function currently in use.

See also:

set_object_activater()

•    Note — The word "activator" is consistently misspelled as "activater" in PCustomizeFundamental methods.

 

get_object_deleter()

static vpp_object_deleter_t *get_object_deleter(PDOM *dom) const;

Get the currently defined object deletion function.

See also:

set_object_deleter()

 

get_object_dirtier()

static vpp_object_dirtier_t *get_object_dirtier(PDOM *dom) const;

Get the object dirty function currently in use.

See also:

set_object_dirtier()

 

get_object_locater()

static vpp_object_locater_t *get_object_locater(PDOM *dom) const;

Get the instance object locator function currently in use.

See also:

set_object_locater()

•    Note — The word "locator" is consistently misspelled as "locater" in PCustomizeFundamental methods.

 

get_object_maker()

static vpp_object_maker_t *get_object_maker(PDOM *dom) const;

Get the currently defined object creation function.

See also:

set_object_maker()

 

get_PClass_fixer()

static vpp_pclass_fixer_t *get_PClass_fixer(PDOM *dom) const;

Get the class fixer function for this thread.

See also:

set_pclass_fixer()

 

get_schema_locater()

static vpp_schema_locater_t* get_schema_locater() const;

Get the schema locator function for this VSession object.

See also:

set_schema_locater()

•    Note — The word "locator" is consistently misspelled as "locater" in PCustomizeFundamental methods.

 

reset()

static void reset(PDOM *dom);

Restore default behavior for all redefined relays.

 

set_call_user_init_flag()

void set_call_user_init_flag(PDOM *dom, o_4b flag );

Specify whether the init() method in PVirtual is called as objects are brought into memory.

To cause init() to be called, specify flag as 1; to restore default behavior, specify flag as 0.

The init() method in PVirtual allows you to initialize objects with transient data when they are first brought into memory. (See init() in PVirtual.)

For example, suppose the Employee class is defined as the following.

class Employee : public PVirtual {

   void *transient_data;

public:

   void  init() {
      // initialize transient_data
   }
};

To cause init() to be called when an instance of Employee is dereferenced:

dom -> beginsession();
PCustomizeFundamental::set_call_user_init_flag( dom, 1 );

Afterwards, dereferencing a link will load the object into the object memory cache and call Employee::init() to initialize transient_data:

Link<Employee> lp = ...;
Employee *ep = lp;

See also set_call_user_init_flag()

 

set_object_activater()

void set_object_activater(

    PDOM                   *dom,
    vpp_object_activater_t *activate_object);

Redefine object activation.

When it is brought into memory, a C++ object must be activated (laid out in memory) before it can be used as a C++ object.

The information needed to activate an instance is contained in its class object, which is an instance of PClassObject<type>. Some activation also occurs when an object is created.

Before a C++ object is brought into memory, VERSANT calls the object_activater() method in PCustomizeFundamental.

By default, the object_activater() function sets the __what, __vtbl, and __vbase pointers per information defined in the VERSANT implementation of the class object, which is an instance of PClassObject<type>.

You can redefine object_activater(), perhaps if you have your own kind of What/Class mechanism, but you probably don't need to. If you do want to define an activation function, you may want to inspect VERSANT's implementation in the file cxxcls/customiz.h.

If the class object for a class has not been found, the PClass_fixer() function will leave the pointer to the class object as NULL. In this case, the default object_activater() function returns the following error:

8040, CXX_NO_CXXCLS: C++ interface does not know about class %s

If you define an object_activater() method, there should be three parameters.

Link

A link of type o_object to the instance .

Class name

A pointer of type char* to the class name.

Class object

A pointer of type PClass* to the desired class object.

The method should return an error code of type o_errno and return NULL if an error occurs. If defined to throw an exception, the exception will not be caught by C++ error handling mechanisms.

To use your activation function, start a session and redefine the calling relay with set_object_activator().

To restore default behavior for all redefined relays, you can end the current session and start a new one or call PCustomizeFundamental::reset().

To restore default behavior for just the relay that activates objects:

PCustomizeFundamental::set_object_activater(dom, NULL);

See also:

get_object_activater(),

set_object_activater() in VSession.

•    Note — The word "activator" is consistently misspelled as "activater" in PCustomizeFundamental methods.

 

set_object_deleter()

void set_object_deleter(

   PDOM                 *dom,
   vpp_object_deleter_t *delete_function );

Redefine C++/VERSANT mechanisms that delete objects from a database.

To delete an object, the delete operator and deleteobj() method call the C/VERSANT o_deleteobj() function.

To redefine what happens when an object is deleted, define a delete function and call this method with your function substituted for the delete_function parameter.

The syntax of o_deleteobj() is:

o_err o_deleteobj( o_object object );

Your redefined function should pass the same arguments and return the same value. Errors will be handled by normal C++ error handling mechanisms. See o_deleteobj() in C/VERSANT Manual for more information.

For example, suppose that you want to redefine the delete mechanisms so that you print the logical object identifier for each deleted object. To do this, you could create the following delete function.

extern "C" {
   o_err my_deleter( o_object x)
   {
      char buf[O_PRINTLOID_SIZE];
      o_err e= o_deleteobj(x);
      if (e!=O_OK) return e;
      o_err ok= o_printloid( x, buf );
      assert(ok==O_OK);
      printf( "Deleted: %s\n", buf );
      return e;
   }
};

Then, after starting a session, redefine the delete relay:

main() {
   ....
   dom->beginsession(...);
   ....
   PCustomizeFundamental::set_object_deleter(dom, my_deleter);
   ....
}

To restore default behavior for all redefined relays, you can end the current session and start a new one or call PCustomizeFundamental::reset().

To restore default behavior for just the delete relay:

PCustomizeFundamental::set_object_maker(dom, o_deleteobj);

See also:

set_object_deleter() in VSession.

 

set_object_dirtier()

void set_object_dirtier(

   PDOM                     *dom,
   vpp_set_object_dirtier_t *dirty_function );

Redefine the default C++/VERSANT mechanism that marks an object for update.

This method changes what happens when the following are called:

dirty()

Method defined in PObject.

preptochange()

Method defined in Link<type> and LinkAny.

To write an object, the above mechanisms call the C/VERSANT function o_preptochange(), which sets a short write lock, marks the object as dirty, and returns O_OK if successful.

The syntax of o_preptochange() is:

o_err o_preptochange( o_object object );

Your redefined function should pass the same arguments and return the same value. Errors will be handled by normal C++ error handling mechanisms. See o_preptochange() in C/VERSANT Manual for more information.

To use your object write function, start a session and redefine the calling relay with the set_object_dirtier().

For example, suppose that you want to redefine the dirty mechanisms so that you print the logical object identifier for each object marked as dirty.

First, create the new dirty function:

extern "C" {
   o_err my_dirty(o_object x)
   {
      char buf[O_PRINTLOID_SIZE];
      o_err e= o_preptochange(x);
      if (e!=O_OK) return e;
      o_err ok= o_printloid( x, buf );
      assert(ok==O_OK);
      printf( "Dirtied: %s\n", buf );
      return e;
   }
};

Then, after starting a session, redefine the dirty relay:

main() {
   ....
   dom->beginsession(...);
   ....
   PCustomizeFundamental::set_object_dirtier(dom, my_dirty);
   ....
}

To restore default behavior for all redefined relays, you can end the current session and start a new one or call PCustomizeFundamental::reset().

To restore default behavior for just the dirty relay:

PCustomizeFundamental::set_object_maker(dom, o_preptochange);

 

set_object_locater()

void set_object_locater(

   PDOM                 *dom,
   vpp_object_locater_t *locator_function);

Redefine the C++/VERSANT mechanism that fetches instance objects from a database.

By default, to read an instance object, the dereference operator ->() and the locateobj() method call the C/VERSANT function o_locateobj(), which finds a specified instance object, sets a specified short lock, pins the object in memory, and returns a pointer to the top of the object.

To redefine this behavior, redefine the locator function and then call this method.

The syntax for o_locateobj() is:

o_u1b* o_locateobj(

   o_object    object,
   o_lockmode  lockmode );

Your redefined function should pass the same arguments and return the same value. See o_locateobj() in the C/VERSANT Manual for more information.

If an error occurs, this function should set o_errno and return NULL. The error will be handled by normal C++ error handling mechanisms.

For example, suppose that you want to redefine read mechanisms so that you print the logical object identifier for each object read.

First, create a new locator function:

extern "C" {
   o_u1b* my_locator(o_object x, o_lockmode lm)
   {
      char buf[O_PRINTLOID_SIZE];
      o_u1b *p= o_locateobj(x, lm);
      if (!p) return p;
      o_err ok= o_printloid( x, buf );
      assert(ok==O_OK);
      printf( "Located: %s\n", buf );
      return p;
   }
};

Then, after starting a session, redefine the object locator relay:

main() {
   ....
   dom->beginsession(...);
   PCustomizeFundamental::set_object_locater(dom,my_locator);
   ....
}

To restore default behavior for all redefined relays, you can end the current session and start a new one or call PCustomizeFundamental::reset().

To restore default behavior for just the object locator:

PCustomizeFundamental::set_object_locater(dom, o_locateobj);

To redefine the locator function for a thread, use the set_object_locater() method in VSession.

•    Note — The word "locator" is consistently misspelled as "locater" in PCustomizeFundamental methods.

 

set_object_maker()

void set_object_maker(

   PDOM               *dom,
   vpp_object_maker_t *create_function);

Redefine C++/VERSANT mechanisms that create objects.

This method changes what happens when the following are called:

O_NEW_PERSISTENT()
O_NEW_PERSISTENT1()
O_NEW_PERSISTENT2()

Macros defined in PObject.

make_copy()

Method defined in Link<type> and LinkAny.

To create an object, the above mechanisms call the C/VERSANT function o_makeobj(), which will create a persistent object of a specified class in the default database, optionally set initial attribute values, optionally pin the new object, and return a link to the new object.

The syntax of o_makeobj() is:

o_object o_makeobj(

   o_object     clsobj,
   o_bufdesc  * initvals,
   o_bool       topin );

Your redefined function should pass the same arguments and return the same value. See o_makeobj() in C/VERSANT Manual for more information.

If an error occurs, this function should set o_errno and return NULL. The error will be handled by normal C++ error handling mechanisms.

To use your object creation function, start a session and then redefine the calling relay with set_object_maker().

For example, suppose you want to redefine the create object mechanisms so that you print the logical object identifier for each new object.

First, create the new object creation function:

extern "C" {
  o_object my_creator( o_object cls, o_bufdesc *bd, o_bool to_pin )
  {
    char buf[O_PRINTLOID_SIZE];
    o_object p = o_makeobj(cls, bd, to_pin);
    if (!p) return p;
    o_err ok = o_printloid( p, buf );
    assert(ok == O_OK);
    printf( "Made: %s\n", buf );
    return p;
  }
};

Then, to use your object creation function, start a session and redefine the object creation relay:

main() {
   ....
   dom->beginsession(...);
   ....
   PCustomizeFundamental::set_object_maker(dom, my_creator);
   ....
}

To restore default behavior for all redefined relays, you can end the current session and start a new one or call PCustomizeFundamental::reset().

To restore default behavior for just the object creator relay:

PCustomizeFundamental::set_object_maker(dom, o_makeobj);

 

set_PClass_fixer()

void set_PClass_fixer(PDOM *dom, vpp_pclass_fixer_t *fix_class)

Assign a data type to a non-C++ object.

C++ objects must have a data type. Normally, a data type is defined by compiling a class definition, stored by loading it into a database as a class object, and made known to an application by linking. In the following cases, a class definition may not have been compiled, stored in a database, and/or linked to an application:

Runtime object

When you create classes at runtime.

In this case, you need to specify to your application both the class and also define PWhat and other things to mimic elements normally defined during schema capture.

Dynamic objects

When you dynamically load classes whose definitions were not linked with your application.

Cheating

When you derive non-C++ classes from C++ classes.

In this case, you can cheat and activate non-C++ objects as if there were the closest C++ class to their true class. This has its limitations. For example, you can use only simple inheritence.

So that you can handle cases in which a class object is not found and you need to create, load, or substitute a class object, before attempting to find a class object, VERSANT internally calls the PClass_fixer() method in PCustomizeFundamental.

The default is for PClass_fixer() to do nothing.

If you define a PClass_fixer() method, there should be three parameters.

Link

A link of type o_object to the instance .

Class name

A pointer of type const char* to the class name.

Class object

A pointer of type PClass** to the desired class object.

In your definition of PClass_fixer(), make the class object parameter point to the desired instance of PClass.

If an error occurs, this function should set o_errno and return NULL. If defined to throw an exception, the exception will not be caught by C++ error handling mechanisms.

To use your function that defines a class, start a session and then redefine the calling relay with set_PClass_fixer().

To restore default behavior for all redefined relays, you can end the current session and start a new one or call PCustomizeFundamental::reset().

To restore default behavior for just the relay that defines a class:

PCustomizeFundamental::set_PClass_fixer(dom, NULL);

See also:

set_pclass_fixer() in VSession.

 

set_schema_locator()

void set_schema_locater(

   PDOM                * dom,
   vpp_schema_locater_t* locator_function);

Redefine the C++/VERSANT mechanism that fetches class objects from a database.

By default, to read a class object, the dereference operator ->() and the locateobj() method call the C/VERSANT function o_locateobj(), which finds a specified instance object, sets a specified short lock, pins the object in memory, and returns a pointer to the top of the object.

To redefine locator behavior for class objects, redefine the locator function and then call this method. Otherwise, all steps are the same as for redefining the locator function for instance objects. See set_object_locater() in VSession for an explanation of object location.

To restore default behavior, call this method and specify o_locateobj() for the locator_function parameter:

PCustomizeFundamental::set_schema_locater(
   dom, o_locateobj);

See also:

set_schema_locater()

•    Note — The word "locator" is consistently misspelled as "locater" in PCustomizeFundamental methods.

 

VSession

 

get_call_user_init_flag()

static o_4b get_call_user_init_flag() const;

Return the current status of the flag used in set_call_user_init_flag() in VSession.

If this method returns 1, then objects will be initialized with the init() method when they are brought into memory. If this method returns 0, then init() will not be called.

See also:

init() in PVirtual

set_call_user_init_flag() in VSession.

 

get_makeobj_thrower()

static vpp_makeobj_thrower_t* get_makeobj_thrower() const;

Get the currently defined object creation exception handler.

See also:

set_makeobj_thrower()

set_object_maker().

 

get_object_activater()

static vpp_object_activater_t* get_object_activater() const;

Get the object activation function currently in use.

See also:

set_object_activater()

•    Note — The word "activator" is consistently misspelled as "activater" in PCustomizeFundamental methods.

 

get_object_deleter()

static vpp_object_deleter_t* get_object_deleter() const;

Get the currently defined object deletion function.

See also:

set_object_deleter()

 

get_object_dirtier()

static vpp_object_dirtier_t* get_object_dirtier() const;

Get the object dirty function currently in use.

See also:

set_object_dirtier()

 

get_object_locater()

static vpp_object_locater_t* get_object_locater() const;

Get the instance object locator function currently in use.

See also:

set_object_locater()

•    Note — The word "locator" is consistently misspelled as "locater" in PCustomizeFundamental methods.

 

get_object_maker()

static vpp_object_maker_t* get_object_maker() const;

Get the currently defined object creation function.

See also:

set_object_maker()

 

get_PClass_fixer()

static vpp_pclass_fixer_t* get_PClass_fixer() const;

Get the class fixer function for this thread.

See also:

set_pclass_fixer()

 

get_schema_locater()

static vpp_schema_locater_t* get_schema_locater() const;

Get the schema locator function for this VSession object.

See also:

set_schema_locater()

•    Note — The word "locator" is consistently misspelled as "locater" in PCustomizeFundamental methods.

 

set_call_user_init_flag()

static void set_call_user_init_flag(o_4b flag);

Specify whether the init() method in PVirtual is called as objects are brought into memory.

To cause init() to be called, specify flag as 1; to restore default behavior, specify flag as 0.

The init() method in PVirtual allows you to initialize objects with transient data when they are first brought into memory.

For example, suppose the Employee class is defined as the following.

class Employee : public PVirtual
{
   void *transient_data;
public:
   void  init() {
      // initialize transient_data
   }
};

To cause init() to be called when an instance of Employee is dereferenced:

VSession::set_call_user_init_flag(1);

Afterwards, dereferencing a link will load the object into the object memory cache and call Employee::init() to initialize transient_data:

Link<Employee> lp = ...;
Employee *ep = lp;

This method is the same as set_call_user_init_flag() in PCustomizeFundamental, except that you can call it for an individual thread.

See also:

init() in PVirtual.

 

set_makeobj_thrower()

static void set_makeobj_thrower( vpp_makeobj_thrower_t *);

To redefine the object creation exception handler, call this method with your redefined function specified as the f parameter.

To restore the default, call this method and specify NULL for the f parameter.

See also:

set_object_maker()

 

set_object_activater()

static void set_object_activater(
   vpp_object_activater_t *activator_function );

Redefine object activation.

When it is brought into memory, a C++ object must be activated (laid out in memory) before it can be used as a C++ object.

The information needed to activate an instance is contained in its class object, which is an instance of PClassObject<type>. Some activation also occurs when an object is created.

Before a C++ object is brought into memory, VERSANT calls the object_activater() method.

By default, the object_activater() function sets the __what, __vtbl, and __vbase pointers per information defined in the VERSANT implementation of the class object, which is an instance of PClassObject<type>.

You can redefine object_activater(), perhaps if you have your own kind of What/Class mechanism, but you probably don't need to. If you do want to define an activation function, you may want to inspect VERSANT's implementation in the file cxxcls/customiz.h.

If the class object for a class has not been found, the PClass_fixer() function will leave the pointer to the class object as NULL. In this case, the default object_activater() function returns the following error:

8040, CXX_NO_CXXCLS: C++ interface does not know about class %s

If you define an object activator function, there should be three parameters.

Link

A link of type o_object to the instance .

Class name

A pointer of type char* to the class name.

Class object

A pointer of type PClass* to the desired class object.

The method should return an error code of type o_errno and return NULL if an error occurs. If defined to throw an exception, the exception will not be caught by C++ error handling mechanisms.

To use your activation function, call this method in a session and specify your activator function in the activator_function parameter.

To restore default behavior for all redefined relays, you can end the current session and start a new one or call the reset() method in VSession.

To restore default behavior for just the relay that activates objects, call this method and specify NULL for the activator_function parameter.

This method is the same as set_object_activater() in PCustomizeFundamental, except for the ability to call it for an individual thread.

•    Note — The word "activator" is consistently misspelled as "activater" in PCustomizeFundamental methods.

 

set_object_deleter()

static void set_object_deleter(
   vpp_object_deleter_t *delete_function );

Redefine C++/VERSANT mechanisms that delete objects from a database.

To delete an object, the delete operator and deleteobj() method call the C/VERSANT o_deleteobj() function.

To redefine what happens when an object is deleted, define a delete function and call this method with your function substituted for the delete_function parameter.

To redefine what happens when an object is deleted, define a delete function and call this method with your function substituted for the delete_function parameter.

The syntax of o_deleteobj() is:

o_err o_deleteobj( o_object object );

Your redefined function should pass the same arguments and return the same value. Errors will be handled by normal C++ error handling mechanisms. See o_deleteobj() in C/VERSANT Manual for more information.

For example, suppose that you want to redefine the delete mechanisms so that you print the logical object identifier for each deleted object. To do this, you could create the following delete function.

extern "C" {
   o_err my_deleter( o_object x)
   {
      char buf[O_PRINTLOID_SIZE];
      o_err e= o_deleteobj(x);
      if (e!=O_OK) return e;
      o_err ok= o_printloid( x, buf );
      assert(ok==O_OK);
      printf( "Deleted: %s\n", buf );
      return e;
   }
};

To restore default behavior for all redefined functions, call reset() in VSession. To restore default behavior for just the delete function, call this method and substitute o_deleteobj for the delete_function parameter.

This method is the same as the set_object_deleter() method in PCustomizeFundamental, except that you can call it for an individual thread.

 

set_object_dirtier()

static void set_object_dirtier(
   vpp_object_dirtier_t *dirty_function );

This method changes what happens when the following are called:

dirty()

Method defined in PObject.

preptochange()

Method defined in Link<type> and LinkAny.

To write an object, the above mechanisms call the C/VERSANT function o_preptochange(), which sets a short write lock, marks the object as dirty, and returns O_OK if successful.

To change the default behavior, define an object dirty function and call this method in a session.

The syntax of o_preptochange() is:

o_err o_preptochange( o_object object );

Your redefined function should pass the same arguments and return the same value. Errors will be handled by normal C++ error handling mechanisms. See o_preptochange() in C/VERSANT Manual for more information.

To restore default behavior for all redefined relays, you can end the current session and start a new one or call reset().

To restore default behavior for just the dirty relay, call this method and specify o_preptochange for the dirty_function parameter.

This method is the same as set_object_dirtier() in PCustomizeFundamental, except for the ability to call it for an individual thread.

See also:

dirty()

preptochange()

 

set_object_locater()

static void set_object_locater(
   vpp_object_locater_t *locator_function);

Redefine the C++/VERSANT mechanism that fetches instance objects from a database.

By default, to read an instance object, the dereference operator ->() and the locateobj() method call the C/VERSANT function o_locateobj(), which finds a specified instance object, sets a specified short lock, pins the object in memory, and returns a pointer to the top of the object.

To redefine this behavior, redefine the locator function and then call this method.

The syntax for o_locateobj() is:

o_u1b *o_locateobj(

   o_object    object,
   o_lockmode  lockmode );

Your redefined function should pass the same arguments and return the same value. See o_locateobj() in the C/VERSANT Manual for more information.

If an error occurs, this function should set o_errno and return NULL. The error will be handled by normal C++ error handling mechanisms.

To restore default behavior, you can end the current session and start a new one or call VSession::reset().

To restore default behavior for just the object locator, call this method and set the locator_function to o_locateobj().

This method is the same as set_object_locater() in PCustomizeFundamental, except that you can call it for an individual thread.

•    Note — The word "locator" is consistently misspelled as "locater" in PCustomizeFundamental methods.

 

set_object_maker()

static void set_object_maker(
   vpp_object_maker_t *create_function );

Redefine C++/VERSANT mechanisms that create objects.

This method changes what happens when the following are called:

Macros defined in PObject:

O_NEW_PERSISTENT()
O_NEW_PERSISTENT1()
O_NEW_PERSISTENT2()

Method defined in Link<type> and LinkAny.

make_copy()

To create an object, the above mechanisms call the C/VERSANT function o_makeobj(), which will create a persistent object of a specified class in the default database, optionally set initial attribute values, optionally pin the new object, and return a link to the new object.

The syntax of o_makeobj() is:

o_object o_makeobj(

   o_object     clsobj,
   o_bufdesc  * initvals,
   o_bool       topin );

Your redefined function should pass the same arguments and return the same value. See o_makeobj() in C/VERSANT Manual for more information.

If an error occurs, this function should set o_errno and return NULL. The error will be handled by normal C++ error handling mechanisms.

To use your object creation function, start a session and then redefine the calling relay with set_object_maker().

For example, suppose you want to redefine the create object mechanisms so that you print the logical object identifier for each new object.

First, create the new object creation function:

extern "C" {
  o_object my_creator( o_object cls, o_bufdesc *bd, o_bool to_pin )
  {
    char buf[O_PRINTLOID_SIZE];
    o_object p = o_makeobj(cls, bd, to_pin);
    if (!p) return p;
    o_err ok = o_printloid( p, buf );
    assert(ok == O_OK);
    printf( "Made: %s\n", buf );
    return p;
  }
};

Then, to use your object creation function, start a session and redefine the object creation relay by specifying your object creation function in the create_function parameter of this method.

To restore default behavior for all redefined relays, you can end the current session and start a new one or call reset().

To restore default behavior for just the object creator relay, call this method and specify o_makeobj for the create_function parameter.

This method is the same as the set_object_maker() method in PCustomizeFundamental, except that you can call it for an individual thread.

 

set_pclass_fixer()

static void set_pclass_fixer(
   vpp_pclass_fixer_t *class_fixer );

Assign a data type to a non-C++ object.

C++ objects must have a data type. Normally, a data type is defined by compiling a class definition, stored by loading it into a database as a class object, and made known to an application by linking. In the following cases, a class definition may not have been compiled, stored in a database, and/or linked to an application:

Runtime object

When you create classes at runtime.

In this case, you need to specify to your application both the class and also define PWhat and other things to mimic elements normally defined during schema capture.

Dynamic objects

When you dynamically load classes whose definitions were not linked with your application.

Cheating

When you derive non-C++ classes from C++ classes.

In this case, you can cheat and activate non-C++ objects as if there were the closest C++ class to their true class. This has its limitations. For example, you can use only simple inheritence.

So that you can handle cases in which a class object is not found and you need to create, load, or substitute a class object, before attempting to find a class object, VERSANT internally calls the PClass_fixer() method in VSession. The default is for PClass_fixer() to do nothing.

To redefine the default behavior, create a class fixer method and then call this method.

If you define a PClass_fixer() method and substitute it for the class_fixer parameter in this method, there should be three parameters:

Link

A link of type o_object to the instance .

Class name

A pointer of type const char* to the class name.

Class object

A pointer of type PClass** to the desired class object.

In your definition of a class fixer method, make the class object parameter point to the desired instance of PClass.

If an error occurs, this function should set o_errno and return NULL. If defined to throw an exception, the exception will not be caught by C++ error handling mechanisms.

To use your function that defines a class, start a session and then redefine the calling relay with set_PClass_fixer().

To restore default behavior for all redefined relays, you can end the current session and start a new one or call reset().

To restore default behavior for just the relay that defines a class, you can call this method and specify NULL for the class_fixer parameter.

This method is the same as set_PClass_fixer() in PCustomizeFundamental, except for a different use of capital letters and the ability to call it for an individual thread.

 

set_schema_locater()

static void set_schema_locater(
   vpp_schema_locater_t *locator_function );

Redefine the C++/VERSANT mechanism that fetches class objects from a database.

By default, to read a class object, the dereference operator ->() and the locateobj() method call the C/VERSANT function o_locateobj(), which finds a specified instance object, sets a specified short lock, pins the object in memory, and returns a pointer to the top of the object.

To redefine locator behavior for class objects, redefine the locator function and then call this method. Otherwise, all steps are the same as for redefining the locator function for instance objects. See set_object_locater() in VSession for an explanation of object location.

To restore default behavior for all redefined relays, you can end the current session and start a new one or call reset().

To restore default behavior, call this method and specify o_locateobj() for the locator_function parameter.

This method is the same as set_schema_locater() in PCustomizeFundamental, except that you can call it for an individual thread.

•    Note — The word "locator" is consistently misspelled as "locater" in PCustomizeFundamental methods.

 

VThread

The VThread class is now obsolete.

The functions described in this section have been moved to the VSession section in this chapter. Although VThread class and methods are still supported by VERSANT, the usage of this class is not ODMG compliant, and is not recommended for new applications.

 

get_call_user_init_flag()

o_4b get_call_user_init_flag() const;

Return the current status of the flag used in set_call_user_init_flag() in VThread.

If this method returns 1, then objects will be initialized with the init() method when they are brought into memory. If this method returns 0, then init() will not be called.

See also:

init() in PVirtual

set_call_user_init_flag() in VThread.

 

get_makeobj_thrower()

vpp_makeobj_thrower_t *get_makeobj_thrower() const;

Get the currently defined object creation exception handler.

See also set_makeobj_thrower() and set_object_maker() in VThread.

 

get_object_activater()

vpp_object_activater_t *get_object_activater() const;

Get the object activation function currently in use.

See set_object_activater() in VThread for an explanation.

Note: the word "activator" is consistently misspelled as "activater" in VThread methods.

 

get_object_deleter()

vpp_object_deleter_t *get_object_deleter() const;

Get the currently defined object deletion function.

See set_object_deleter() in VThread for an explanation.

 

get_object_dirtier()

vpp_object_dirtier_t *get_object_dirtier() const;

Get the object dirty function currently in use.

See set_object_dirtier() in VThread for an explanation.

 

get_object_locater()

vpp_object_locater_t *get_object_locater() const;

Get the instance object locator function currently in use.

See set_object_locater() in VThread for an explanation of the object locator function.

Note: the word "locator" is consistently misspelled as "locater" in VThread methods.

 

get_object_maker()

vpp_object_maker_t *get_object_maker() const;

Get the currently defined object creation function.

See set_object_maker() in VThread for an explanation.

 

get_PClass_fixer()

vpp_pclass_fixer_t *get_PClass_fixer() const;

Get the class fixer function for this thread.

See set_pclass_fixer() in VThread for an explanation.

 

reset()

void reset();

Restore default behavior for C++/VERSANT mechanisms for creating, reading, writing, deleting, and activating objects.

This method is similar to the reset() method in PCustomizeFundamental, except that it can be used on individual threads.

 

set_call_user_init_flag()

void set_call_user_init_flag(o_4b flag);

Specify whether the init() method in PVirtual is called as objects are brought into memory.

To cause init() to be called, specify flag as 1; to restore default behavior, specify flag as 0.

The init() method in PVirtual allows you to initialize objects with transient data when they are first brought into memory.

For example, suppose the Employee class is defined as the following.

class Employee : public PVirtual {

   void *transient_data;

public:

   void  init() {
      // initialize transient_data
   }
};

To cause init() to be called when an instance of Employee is dereferenced:

VThread mythread;
mythread.set_call_user_init_flag(1);

Afterwards, dereferencing a link will load the object into the object memory cache and call Employee::init() to initialize transient_data:

Link<Employee> lp = ...;
Employee *ep = lp;

This method is the same as set_call_user_init_flag() in PCustomizeFundamental, except that you can call it for an individual thread.

See also:

init() in PVirtual.

 

set_makeobj_thrower()

void set_makeobj_thrower( vpp_makeobj_thrower_t *);

To redefine the object creation exception handler, call this method with your redefined function specified as the f parameter.

To restore the default, call this method and specify NULL for the f parameter.

See also:

set_object_maker() in VThread.

 

set_object_activater()

void set_object_activater(
   vpp_object_activater_t *activator_function );

Redefine object activation.

When it is brought into memory, a C++ object must be activated (laid out in memory) before it can be used as a C++ object.

The information needed to activate an instance is contained in its class object, which is an instance of PClassObject<type>. Some activation also occurs when an object is created.

Before a C++ object is brought into memory, VERSANT calls the object_activater() method.

By default, the object_activater() function sets the __what, __vtbl, and __vbase pointers per information defined in the VERSANT implementation of the class object, which is an instance of PClassObject<type>.

You can redefine object_activater(), perhaps if you have your own kind of What/Class mechanism, but you probably don't need to. If you do want to define an activation function, you may want to inspect VERSANT's implementation in the file cxxcls/customiz.h.

If the class object for a class has not been found, the PClass_fixer() function will leave the pointer to the class object as NULL. In this case, the default object_activater() function returns the following error:

8040, CXX_NO_CXXCLS: C++ interface does not know about class %s

If you define an object activator function, there should be three parameters.

Link

A link of type o_object to the instance .

Class name

A pointer of type char* to the class name.

Class object

A pointer of type PClass* to the desired class object.

The method should return an error code of type o_errno and return NULL if an error occurs. If defined to throw an exception, the exception will not be caught by C++ error handling mechanisms.

To use your activation function, call this method in a session and specify your activator function in the activator_function parameter.

To restore default behavior for all redefined relays, you can end the current session and start a new one or call the reset() method in VThread.

To restore default behavior for just the relay that activates objects, call this method and specify NULL for the activator_function parameter.

This method is the same as set_object_activater() in PCustomizeFundamental, except for the ability to call it for an individual thread.

Note: the word "activator" is consistently misspelled as "activater" in VThread methods.

 

set_object_deleter()

void set_object_deleter(
   vpp_object_deleter_t *delete_function );

Redefine C++/VERSANT mechanisms that delete objects from a database.

To delete an object, the delete operator and deleteobj() method call the C/VERSANT o_deleteobj() function.

To redefine what happens when an object is deleted, define a delete function and call this method with your function substituted for the delete_function parameter.

To redefine what happens when an object is deleted, define a delete function and call this method with your function substituted for the delete_function parameter.

The syntax of o_deleteobj() is:

o_err o_deleteobj( o_object object );

Your redefined function should pass the same arguments and return the same value. Errors will be handled by normal C++ error handling mechanisms. See o_deleteobj() in C/VERSANT Manual for more information.

For example, suppose that you want to redefine the delete mechanisms so that you print the logical object identifier for each deleted object. To do this, you could create the following delete function.

extern "C" {
   o_err my_deleter( o_object x)
   {
      char buf[O_PRINTLOID_SIZE];
      o_err e= o_deleteobj(x);
      if (e!=O_OK) return e;
      o_err ok= o_printloid( x, buf );
      assert(ok==O_OK);
      printf( "Deleted: %s\n", buf );
      return e;
   }
};

To restore default behavior for all redefined functions, call reset() in VThread. To restore default behavior for just the delete function, call this method and substitute o_deleteobj for the delete_function parameter.

This method is the same as the set_object_deleter() method in PCustomizeFundamental, except that you can call it for an individual thread.

 

set_object_dirtier()

void set_object_dirtier(
   vpp_object_dirtier_t *dirty_function );

This method changes what happens when the following are called:

dirty()

Method defined in PObject.

preptochange()

Method defined in Link<type> and LinkAny.

To write an object, the above mechanisms call the C/VERSANT function o_preptochange(), which sets a short write lock, marks the object as dirty, and returns O_OK if successful.

To change the default behavior, define an object dirty function and call this method in a session.

The syntax of o_preptochange() is:

o_err o_preptochange( o_object object );

Your redefined function should pass the same arguments and return the same value. Errors will be handled by normal C++ error handling mechanisms. See o_preptochange() in C/VERSANT Manual for more information.

To restore default behavior for all redefined relays, you can end the current session and start a new one or call the reset() method in VThread.

To restore default behavior for just the dirty relay, call this method and specify o_preptochange for the dirty_function parameter.

This method is the same as set_object_dirtier() in PCustomizeFundamental, except for the ability to call it for an individual thread.

 

set_object_locater()

void set_object_locater(
   vpp_object_locater_t *locator_function);

Redefine the C++/VERSANT mechanism that fetches instance objects from a database.

By default, to read an instance object, the dereference operator ->() and the locateobj() method call the C/VERSANT function o_locateobj(), which finds a specified instance object, sets a specified short lock, pins the object in memory, and returns a pointer to the top of the object.

To redefine this behavior, redefine the locator function and then call this method.

The syntax for o_locateobj() is:

o_u1b* o_locateobj(

   o_object    object,
   o_lockmode  lockmode );

Your redefined function should pass the same arguments and return the same value. See o_locateobj() in the C/VERSANT Manual for more information.

If an error occurs, this function should set o_errno and return NULL. The error will be handled by normal C++ error handling mechanisms.

To restore default behavior, you can end the current session and start a new one or call VThread::reset().

To restore default behavior for just the object locator, call this method and set the locator_function to o_locateobj():

This method is the same as set_object_locater() in PCustomizeFundamental, except that you can call it for an individual thread.

Note: the word "locator" is consistently misspelled as "locater" in VThread methods.

 

set_object_maker()

void set_object_maker(
   vpp_object_maker_t *create_function );

Redefine C++/VERSANT mechanisms that create objects.

This method changes what happens when the following are called:

O_NEW_PERSISTENT()
O_NEW_PERSISTENT1()
O_NEW_PERSISTENT2()

Macros defined in PObject.

make_copy()

Method defined in Link<type> and LinkAny.

To create an object, the above mechanisms call the C/VERSANT function o_makeobj(), which will create a persistent object of a specified class in the default database, optionally set initial attribute values, optionally pin the new object, and return a link to the new object.

The syntax of o_makeobj() is:

o_object o_makeobj(

   o_object     clsobj,
   o_bufdesc  * initvals,
   o_bool       topin );

Your redefined function should pass the same arguments and return the same value. See o_makeobj() in C/VERSANT Manual for more information.

If an error occurs, this function should set o_errno and return NULL. The error will be handled by normal C++ error handling mechanisms.

To use your object creation function, start a session and then redefine the calling relay with set_object_maker().

For example, suppose you want to redefine the create object mechanisms so that you print the logical object identifier for each new object.

First, create the new object creation function:

extern "C" {
  o_object my_creator( o_object cls, o_bufdesc *bd, o_bool to_pin )
  {
    char buf[O_PRINTLOID_SIZE];
    o_object p = o_makeobj(cls, bd, to_pin);
    if (!p) return p;
    o_err ok = o_printloid( p, buf );
    assert(ok == O_OK);
    printf( "Made: %s\n", buf );
    return p;
  }
};

Then, to use your object creation function, start a session and redefine the object creation relay by specifying your object creation function in the create_function parameter of this method.

To restore default behavior for all redefined relays, you can end the current session and start a new one or call reset().

To restore default behavior for just the object creator relay, call this method and specify o_makeobj for the create_function parameter.

This method is the same as the set_object_maker() method in PCustomizeFundamental, except that you can call it for an individual thread.

 

set_pclass_fixer()

void set_pclass_fixer(
   vpp_pclass_fixer_t *class_fixer );

Assign a data type to a non-C++ object.

C++ objects must have a data type. Normally, a data type is defined by compiling a class definition, stored by loading it into a database as a class object, and made known to an application by linking. In the following cases, a class definition may not have been compiled, stored in a database, and/or linked to an application:

Runtime object

When you create classes at runtime.

In this case, you need to specify to your application both the class and also define PWhat and other things to mimic elements normally defined during schema capture.

Dynamic objects

When you dynamically load classes whose definitions were not linked with your application.

Cheating

When you derive non-C++ classes from C++ classes.

In this case, you can cheat and activate non-C++ objects as if there were the closest C++ class to their true class. This has its limitations. For example, you can use only simple inheritance.

So that you can handle cases in which a class object is not found and you need to create, load, or substitute a class object, before attempting to find a class object, VERSANT internally calls the PClass_fixer() method in VThread. The default is for PClass_fixer() to do nothing.

To redefine the default behavior, create a class fixer method and then call this method.

If you define a PClass_fixer() method and substitute it for the class_fixer parameter in this method, there should be three parameters:

Link

A link of type o_object to the instance .

Class name

A pointer of type const char* to the class name.

Class object

A pointer of type PClass** to the desired class object.

In your definition of a class fixer method, make the class object parameter point to the desired instance of PClass.

If an error occurs, this function should set o_errno and return NULL. If defined to throw an exception, the exception will not be caught by C++ error handling mechanisms.

To use your function that defines a class, start a session and then redefine the calling relay with set_PClass_fixer().

To restore default behavior for all redefined relays, you can end the current session and start a new one or call reset().

To restore default behavior for just the relay that defines a class, you can call this method and specify NULL for the class_fixer parameter.

This method is the same as set_PClass_fixer() in PCustomizeFundamental, except for a different use of capital letters and the ability to call it for an individual thread.

 

set_schema_locater()

void set_schema_locater(
   vpp_schema_locater_t *locator_function );

Redefine the C++/VERSANT mechanism that fetches class objects from a database.

By default, to read a class object, the dereference operator ->() and the locateobj() method call the C/VERSANT function o_locateobj(), which finds a specified instance object, sets a specified short lock, pins the object in memory, and returns a pointer to the top of the object.

To redefine locator behavior for class objects, redefine the locator function and then call this method. Otherwise, all steps are the same as for redefining the locator function for instance objects. See set_object_locater() in VThread for an explanation of object location.

To restore default behavior, call this method and specify o_locateobj() for the locator_function parameter.

This method is the same as set_schema_locater() in PCustomizeFundamental, except that you can call it for an individual thread.

Note: the word "locator" is consistently misspelled as "locater" in VThread methods.

 

 

 


This online documentation is confidential and proprietary to Versant Corporation and is licensed to you, or to your organization, pursuant to the terms of an agreement between you and Versant that restricts the use of this documentation. Please refer to the agreement for more information or call Versant at 510-789-1500 with any questions.