Hello everyone,
As the subject says, I'm in the process of creating such a beast. As such, I have two session factories, unlike what is usually recommended, but it's a necessity here.
The first one is dedicated to accessing, and modifying, the object definitions (a POJO mapped to a simple two columns table, one with the entity name, the other with the contents of the Hibernate mapping file). I then use the stored definitions to rebuild the second session factory.
This second session factory is therefore dynamically updated. I spawn sessions with either dynamic-map mode or dom4j mode. The user never sees Hibernate sessions directly, instead I spawn an object from which it can do its stuff (getting the object list, getting an object template to fill, listing objects, writing objects). The object is created with its creation date as a field, and as such I can detect whether the configuration (and therefore the session factory) has been updated in the meanwhile, and proceed only if the template it uses is valid (object exists, its editable fields haven't changed, etc). This is what I use to rebuild the configuration (wlock is the writeLock() or a ReentrantReadWriteLock, persistor has all mappings "pre-digested"):
Code:
final Configuration newcfg
= new Configuration().addProperties(defaultProperties);
wlock.lock();
try {
for (final String mapping : persistor.getMappings())
newcfg.addXML(mapping);
newcfg.buildMappings();
cfg = newcfg;
sf = cfg.buildSessionFactory();
ObjectCache.reset(cfg);
lastModified = new Date();
} catch (Exception e) {
throw new InvalidMappingException(
"Failed to reload configuration! Keeping old one", e
);
} finally {
wlock.unlock();
}
I can add and remove mappings, and when I regenerate the session factory, Hibernate updates the tables for me, so far so good. But it doesn't delete tables, however. Is there a way to get the DDL from Hibernate to delete a table?
Also, I haven't played yet with "multiple column fields" or even foreign keys. Here is how I detect what fields can be edited, what fields are compulsory. So far, it works, but is there a better way?
Code:
// Here we have:
// r = cfg.getClassMapping(objectName).getRootClass();
//
// Constructor - descriptor is an org.dom4j.Document
public ObjectDescriptor(final RootClass r)
{
descriptor = DocumentHelper.createDocument();
final Element e = descriptor.addElement("object");
e.addAttribute("name", r.getEntityName());
e.add(createField(r.getIdentifierProperty()));
@SuppressWarnings("unchecked")
final Iterator<Property> i = r.getPropertyIterator();
while (i.hasNext())
e.add(createField(i.next()));
}
// The createField() method
private Element createField(final Property p)
{
final Element result = DocumentHelper.createElement("field");
result.addAttribute("name", p.getName());
final Element
optional = result.addElement("optional"),
editable = result.addElement("editable"),
type = result.addElement("type");
optional.setText(Boolean.toString(p.isOptional()));
type.setText(p.getType().getName());
editable.setText("true");
final Value v = p.getValue();
if (v.isSimpleValue()) {
final SimpleValue sv = (SimpleValue) v;
if (sv.getIdentifierGeneratorProperties() != null)
editable.setText("false");
}
return result;
}
Thanks,