Jump to: navigation, search

Teneo/Hibernate/Extensions

< Teneo‎ | Hibernate
Revision as of 15:01, 21 January 2010 by Mtaal.elver.org (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The mapping and annotation logic of Teneo is implemented in many different classes. Teneo makes it possible to replace the implementation of these classes with a custom-implemented class. Examples of these extension points are the EntityNameStrategy and SqlNameStrategy classes.

Currently Teneo has around 50 ExtensionPoints which can be replaced by a custom implementation.


ExtensionPoint definition

An ExtensionPoint has a name which is always a class or interface name. For each ExtensionPoint Teneo will register a default Extension. An extension defines for an ExtensionPoint which class will implement the ExtensionPoint. An extension can be defined as a singleton (only one instance per ExtensionManager). Teneo will register so-called default extensions. A user can register his/her own custom (non-default) extensions. Teneo will never override a custom Extension.


Find all ExtensionPoints

It is easy to find all the ExtensionPoints of Teneo, in Eclipse do ctrl/shift-h (open type in hierarchy, see under the Navigate menu) then enter ExtensionPoint and select the org.eclipse.emf.teneo.extension.ExtensionPoint. Eclipse should then show all the classes/interfaces implementing ExtensionPoint. These are all the Teneo ExtensionPoints.

The name of the ExtensionPoint is the fully classified name of the class/interface implementing the ExtensionPoint interface. This same class or interface also defines the interface which must be implemented by the custom class.

The ExtensionPoints can be divided in different groups:

  • org.eclipse.emf.teneo.annotations.mapper.*: ExtensionPoints which take care of adding default jpa annotations to the model. There are different annotators for different cases (one-to-many, many-to-one, etc.).
  • org.eclipse.emf.teneo.mapping.strategy.*: ExtensionPoints related to entitynaming and sql naming. See below.
  • org.eclipse.emf.teneo.hibernate.mapper.*: these ExensionPoints take care of creating the hibernate mapping file from the jpa annotated model.
  • org.eclipse.emf.teneo.hibernate.mapping.*: these ExtensionPoints are mostly implementations of the hibernate accessor and hibernate getter and setter interfaces. These propertyhandlers are used to access the EObject properties.
  • org.eclipse.emf.teneo.hibernate.mapping.elist.*: these ExtensionPoints are the EList and FeatureMap implementations used by Teneo.
  • org.eclipse.emf.teneo.jpox.mapper.*: ExtensionPoints which take care of creating the jpox/jdo mapping file.


ExtensionManager

Extensions are managed by an ExtensionManager. One ExtensionManager is created for each DataStore (or one mapping action in the HbHelper). Extension instances are therefore not shared over different DataStores. An ExtensionManager can be used to register a custom Extension or create an instance of an ExtensionPoint.

// register an extension before calling initialize on the datastore
 
// create the datastore
final HbDataStore hds = HbHelper.INSTANCE.createRegisterDataStore("test");
 
// get the extensionmanager used by the datastore 
final ExtensionManager extensionManager = hds.getExtensionManager();
 
// and set the custom extension using the ExtensionPoint name and the 
// class name of the custom ExtensionPoint. Note all names are fully qualified!
extensionManager.registerExtension(EntityNameStrategy.class.getName(), QualifyingEntityNameStrategy.class.getName());

Then an ExtensionPoint instance can be retrieved like this (this is not something a user of Teneo needs to do, this is done by Teneo internally):

final EntityNameStrategy ens = extensionManager.getExtension(EntityNameStrategy.class);

Requirements for custom Extension:

  • The custom extension must implement the interface of the ExtensionPoint or extend the class defined by the ExtensionPoint.
  • It must have a zero argument constructor.
  • Teneo creates an ExtensionManager always through the ExtensionManagerFactory.getInstance(). You can set your own ExtensionManagerFactory by calling ExtensionManagerFactory.setInstance(...).


ExtensionManagerAware, ExtensionInitializable

There are two other relevant interfaces which can be implemented by an ExtensionPoint:

  • ExtensionManagerAware: an instance which implements this interface will 'receive' the ExtensionManager which created it. This is done directly after it has been instantiated by the ExtensionManager.
  • ExtensionInitializable: an instance which implements this interface will be initialized just after the instance has been created and after the ExtensionManager has been set (if the instance is ExtensionManagerAware). Initialization is done through the method defined by this interface.


EntityNameStrategy ExtensionPoint (org.eclipse.emf.teneo.mapping.strategy.EntityNameStrategy)

During the mapping action Teneo determines the entity name for each EClass. The entity name is reflected in the mapping file. The entity name is important because it needs to be unique and it can be used in hql queries. There are currently three entity naming strategies:

  • org.eclipse.emf.teneo.mapping.strategy.impl.EntityResolvingNameStrategy ( default ): uses the name set in the @Entity annotation of the EClass, if this annotation is not present then the EClass name is used. If two eclasses in different epackages have the same name then a name-clash will occur. However this can easily be 'repaired' by setting an @Entity annotation on these EClasses.
  • org.eclipse.emf.teneo.mapping.strategy.impl.ClassicEntityNameStrategy: is deprecated, uses the eclass name. If two eclasses in different epackages have the same name then a name-clash will occur.
  • org.eclipse.emf.teneo.mapping.strategy.impl.QualifyingEntityNameStrategy: creates an entity name by prefixing the eclass name with the epackage nsprefix or the name of the epackage. This always results in unique entity names.


SqlNameStrategy ExtensionPoint (org.eclipse.emf.teneo.mapping.strategy.SQLNameStrategy)

The sql naming strategy is an important strategy because a trade-off needs to be made between short and understandable names and long and unique names. Currently Teneo has three naming strategies:

  • ClassicSQLNameStrategy: which is aimed at backward compatibility.
  • TeneoSQLNameStrategy ( default ): is very similar to ClassicSQLNameStrategy but has better handling of table/column names which are too long. Note uses the EClass name and not the Entity name to create join column names.
  • TeneoNewSQLNameStrategy: is very similar to the TeneoSQLNameStrategy with one important difference: uses the entity name and not the EClass name to create the join column names.

In future releases of Teneo new naming strategies will be added to separately support the short-understandable and long-unique naming strategies.

Using the ExtensionPoint mechanism the current sql naming strategy can be replaced by a custom strategy.

ClassicSQLNameStrategy

Is implemented by the Extension: org.eclipse.emf.teneo.mapping.strategy.impl.ClassicSQLNameStrategy. This strategy has the following naming behavior:

  • PrimaryKeyJoinColumn: the name of the join columns from the joined-subclass table to the parent class table. The join column name is the concatenation of the super entity name and the id feature name of the super entity.
  • SecondaryTablePrimaryKeyJoinColumn: the name of the primary key from the secondary table to the main table. Is the name of the id feature of the main type.
  • Table name: the entity name.
  • Column name: the name for a 'simple' column: the efeature name.
  • Foreign Key name: the name of the foreign key created for an EReference, the concatenation of the entity name, '_' and the EReference name.
  • ManyToOneJoinColumn: the join column name created for a single EReference, depends on the option JOIN_COLUMN_NAMING_STRATEGY.
  • OneToMany join column for EAttribute: the join columns used for a many eattribute (list of primitive types). Depends on the JOIN_COLUMN_NAMING_STRATEGY setting.
  • OneToMany join column for EReference: the join columns used for a many ereference. Depends on the JOIN_COLUMN_NAMING_STRATEGY setting.
  • Join table join columns: the join columns used in the join table for a many-to-many relation or a one-to-many with a join table. Depends on the JOIN_COLUMN_NAMING_STRATEGY option.
  • Join Table Name for many EAttribute: the name of the join table, is the concatenation of the entity name and the EAttribute name.
  • Join Table Name for many EReference: the name of the join table, depends on the JOIN_TABLE_NAMING_STRATEGY option.
  • Version, Discriminator, IdBagId, Synthetic ID column names: are all option controlled.

TeneoSQLNameStrategy (default)

Is implemented by the Extension: org.eclipse.emf.teneo.mapping.strategy.impl.TeneoSQLNameStrategy. This strategy has for the most part the same behavior as the ClassicSQLNameStrategy. Currently for the following function it has a different behavior:

Truncation of long sql names: it is possible to set the maximum length of sql names using the MAXIMUM_SQL_NAME_LENGTH option. Sql names are derived from model names, for model names it is guaranteed that certain names are unique. However if a unique name has to be truncated because of length constraints then name clashes can occur. For example assume an ECLass Child which has an efeature parent (which can be many=true). The logical name for the join table for this efeature would be 'child_parent' and for the Child EClass the table would be 'child'. However assume now that a sql name length constraint applies of 4 then the join table name will become 'chil', and the table name of the Child EClass would also become 'chil'. This results in a name clash.

The truncation implemented in this name strategy performs truncation by removing vowels (the a, e, i, o, u) from the table and column names. It will do this in the order u, o, a, e, i. The first character of the original name will always be preserved (for example user will be truncated to usr). If vowel removal did not result in names with the correct length it will do further truncation. Further truncation is done by splitting the name using the _ separator (common separator in sql naming) and then truncating the longest part one character at the time.

Note that you can easily extend this class and pass your own 'removable' characters. Using the extensions mechanism you can then replace the TeneoSQLNameStrategy with your own.

Some examples:

  • child_parent (max length: 3) will be converted to c_p
  • child_father_mother (max length: 1) will be converted to c_f_m
  • child_parent (max length: 7) will be converted to chl_prn
  • child (max length: 4) will be converted to chld
  • child.parent.id (max length: 14) will be converted to child_prent_id
  • child.parent.id (max length: 10) will be converted to chl_prn_d
  • user.parent (max length: 7) will be converted to usr_prn


ClassLoaderStrategy ExtensionPoint (org.eclipse.emf.teneo.classloader.ClassLoaderStrategy)

The default extension manager will load all the extensions using the classloader strategy registered for the ClassLoaderStrategy ExtensionPoint. The ClassLoaderStrategy extension itself is loaded through the ClassLoaderStrategy set in the org.eclipse.emf.teneo.classloader.ClassLoaderResolver.

The default class loading strategy of Teneo is the ContextClassLoaderStrategy (see here).

Future Enhancements

The following future enhancements are considered:

  • ExtensionFactory: instead of registering the class of the Extension it can also be usefull to be able to register a factory which creates the required extension instance.
  • OSGI-integration: it is the intention to make the Teneo extension mechanism osgi compliant.
  • More *Aware interfaces: it can be usefull to also support other Aware constructions such as PersistenceOptions aware or DataStore aware.