package pt.ist.fenixframework.pstm;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.ojb.broker.metadata.ClassDescriptor;
import org.apache.ojb.broker.metadata.CollectionDescriptor;
import org.apache.ojb.broker.metadata.DescriptorRepository;
import org.apache.ojb.broker.metadata.FieldDescriptor;
import org.apache.ojb.broker.metadata.MetadataManager;
import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
import pt.ist.fenixframework.core.DomainObjectAllocator;
import pt.ist.fenixframework.dml.DomainClass;
import pt.ist.fenixframework.dml.DomainEntity;
import pt.ist.fenixframework.dml.DomainModel;
import pt.ist.fenixframework.dml.Role;
import pt.ist.fenixframework.dml.Slot;
import pt.ist.fenixframework.pstm.ojb.ReadOnlyPersistentField;
import pt.ist.fenixframework.pstm.ojb.WriteOnlyPersistentField;
import pt.ist.fenixframework.pstm.repository.DbUtil;
/**
* @author - Shezad Anavarali (shezad@ist.utl.pt)
*
*/
public class OJBMetadataGenerator {
private static final String DOMAIN_OBJECT_CLASSNAME = "net.sourceforge.fenixedu.domain.DomainObject";
private static final String FRAMEWORK_PACKAGE = "pt.ist.fenixframework.pstm";
private static String classToDebug = null;
// This can go since now it will be taken care of by the init itself.
// private static void addPersistentRootClassDescriptor(FenixDomainModel
// domainModel,
// DescriptorRepository repository) throws Exception {
// Class persRootClass = PersistentRoot.class;
// ClassDescriptor classDescriptor = new ClassDescriptor(repository);
// classDescriptor.setClassOfObject(persRootClass);
// classDescriptor.setTableName("FF$PERSISTENT_ROOT");
// setFactoryMethodAndClass(classDescriptor);
//
// addPrimaryFieldDescriptor(domainModel, "oid", "long", 1, classDescriptor,
// persRootClass);
// addFieldDescriptor(domainModel, PersistentRoot.SLOT_NAME, "long", 2,
// classDescriptor, persRootClass);
//
// repository.getDescriptorTable().put(PersistentRoot.class.getName(),
// classDescriptor);
// }
public static void updateOJBMappingFromDomainModel(DomainModel domainModel) throws Exception {
final DescriptorRepository descriptorRepository = MetadataManager.getInstance().getGlobalRepository();
Map ojbMetadata = descriptorRepository.getDescriptorTable();
// addPersistentRootClassDescriptor(domainModel, descriptorRepository);
for (final Iterator iterator = domainModel.getClasses(); iterator.hasNext();) {
final DomainClass domClass = (DomainClass) iterator.next();
final String classname = domClass.getFullName();
if (!classname.equals(DOMAIN_OBJECT_CLASSNAME)) {
final Class clazz = Class.forName(classname);
final ClassDescriptor classDescriptor = new ClassDescriptor(descriptorRepository);
classDescriptor.setClassOfObject(clazz);
classDescriptor.setTableName(getExpectedTableName(domClass));
ojbMetadata.put(domClass.getFullName(), classDescriptor);
}
}
for (final Iterator iterator = domainModel.getClasses(); iterator.hasNext();) {
final DomainClass domClass = (DomainClass) iterator.next();
final String classname = domClass.getFullName();
if (!classname.equals(DOMAIN_OBJECT_CLASSNAME)) {
final Class clazz = Class.forName(classname);
final ClassDescriptor classDescriptor = (ClassDescriptor) ojbMetadata.get(classname);
addClassExtentOfAncesterClassDescriptors(ojbMetadata, domClass.getSuperclass(), clazz);
if (classDescriptor != null) {
setFactoryMethodAndClass(classDescriptor);
updateFields(domainModel, classDescriptor, domClass, ojbMetadata, clazz);
if (!Modifier.isAbstract(clazz.getModifiers())) {
updateRelations(classDescriptor, domClass, ojbMetadata, clazz);
}
if (classToDebug != null && classDescriptor.getClassNameOfObject().contains(classToDebug)) {
System.out.println(classDescriptor.toXML());
}
}
}
}
}
private static void addClassExtentOfAncesterClassDescriptors(final Map ojbMetadata, final DomainEntity domainEntity,
final Class clazz) {
if (domainEntity != null && domainEntity instanceof DomainClass) {
final DomainClass domainClass = (DomainClass) domainEntity;
final String ancesterClassname = domainClass.getFullName();
if (!ancesterClassname.equals(DOMAIN_OBJECT_CLASSNAME)) {
final ClassDescriptor classDescriptor = (ClassDescriptor) ojbMetadata.get(ancesterClassname);
classDescriptor.addExtentClass(clazz);
addClassExtentOfAncesterClassDescriptors(ojbMetadata, domainClass.getSuperclass(), clazz);
}
}
}
protected static String getExpectedTableName(final DomainClass domainClass) {
// Shameless hack to make OJB map to the special framework tables
if (domainClass.getFullName().startsWith(FRAMEWORK_PACKAGE)) {
return "FF$" + getTableName(domainClass.getName());
}
if (domainClass.getFullName().equals(DOMAIN_OBJECT_CLASSNAME)) {
return null;
}
if (domainClass.getSuperclass() == null
|| (domainClass.getSuperclass() instanceof DomainClass && domainClass.getSuperclass().getFullName()
.equals(DOMAIN_OBJECT_CLASSNAME))) {
return getTableName(domainClass.getName());
}
return domainClass.getSuperclass() instanceof DomainClass ? getExpectedTableName((DomainClass) domainClass
.getSuperclass()) : null;
}
private static String getTableName(final String name) {
final StringBuilder stringBuilder = new StringBuilder();
boolean isFirst = true;
for (final char c : name.toCharArray()) {
if (isFirst) {
isFirst = false;
stringBuilder.append(Character.toUpperCase(c));
} else {
if (Character.isUpperCase(c)) {
stringBuilder.append('_');
stringBuilder.append(c);
} else {
stringBuilder.append(Character.toUpperCase(c));
}
}
}
return stringBuilder.toString();
}
private static void setFactoryMethodAndClass(ClassDescriptor cld) {
// this will eventually disappear
cld.setFactoryClass(DomainObjectAllocator.class);
}
protected static void updateFields(final DomainModel domainModel, final ClassDescriptor classDescriptor,
final DomainClass domClass, final Map ojbMetadata, final Class persistentFieldClass) throws Exception {
DomainEntity domEntity = domClass;
int fieldID = 1;
addPrimaryFieldDescriptor(domainModel, "idInternal", "int", fieldID++, classDescriptor, persistentFieldClass);
// write the OID also
addFieldDescriptor(domainModel, "oid", "long", fieldID++, classDescriptor, persistentFieldClass);
while (domEntity instanceof DomainClass) {
DomainClass dClass = (DomainClass) domEntity;
Iterator<Slot> slots = dClass.getSlots();
while (slots.hasNext()) {
Slot slot = slots.next();
String slotName = slot.getName();
String slotType = slot.getSlotType().getDomainName();
addFieldDescriptor(domainModel, slotName, slotType, fieldID++, classDescriptor, persistentFieldClass);
}
for (Role role : dClass.getRoleSlotsList()) {
String roleName = role.getName();
if ((role.getMultiplicityUpper() == 1) && (roleName != null)) {
String foreignOidField = "oid" + StringUtils.capitalize(roleName);
addFieldDescriptor(domainModel, foreignOidField, "Long", fieldID++, classDescriptor, persistentFieldClass);
}
}
domEntity = dClass.getSuperclass();
}
}
protected static void addPrimaryFieldDescriptor(DomainModel domainModel, String slotName, String slotType, int fieldID,
ClassDescriptor classDescriptor, Class persistentFieldClass) throws Exception {
FieldDescriptor fieldDescriptor = new FieldDescriptor(classDescriptor, fieldID);
fieldDescriptor.setColumnName(DbUtil.convertToDBStyle(slotName));
fieldDescriptor.setAccess("readwrite");
fieldDescriptor.setPrimaryKey(true);
fieldDescriptor.setAutoIncrement(true);
PersistentField persistentField = new ReadOnlyPersistentField(persistentFieldClass, slotName);
fieldDescriptor.setPersistentField(persistentField);
String sqlType = domainModel.getJdbcTypeFor(slotType);
fieldDescriptor.setColumnType(sqlType);
classDescriptor.addFieldDescriptor(fieldDescriptor);
}
protected static void addFieldDescriptor(DomainModel domainModel, String slotName, String slotType, int fieldID,
ClassDescriptor classDescriptor, Class persistentFieldClass) throws Exception {
if (classDescriptor.getFieldDescriptorByName(slotName) == null) {
FieldDescriptor fieldDescriptor = new FieldDescriptor(classDescriptor, fieldID);
fieldDescriptor.setColumnName(DbUtil.convertToDBStyle(slotName));
fieldDescriptor.setAccess("readwrite");
PersistentField persistentField = new ReadOnlyPersistentField(persistentFieldClass, slotName);
fieldDescriptor.setPersistentField(persistentField);
String sqlType = domainModel.getJdbcTypeFor(slotType);
fieldDescriptor.setColumnType(sqlType);
classDescriptor.addFieldDescriptor(fieldDescriptor);
}
}
protected static void updateRelations(final ClassDescriptor classDescriptor, final DomainClass domClass, Map ojbMetadata,
Class persistentFieldClass) throws Exception {
DomainEntity domEntity = domClass;
while (domEntity instanceof DomainClass) {
DomainClass dClass = (DomainClass) domEntity;
// roles
Iterator roleSlots = dClass.getRoleSlots();
while (roleSlots.hasNext()) {
Role role = (Role) roleSlots.next();
String roleName = role.getName();
if (roleName == null) {
continue;
}
if (domClass.getFullName().equals("net.sourceforge.fenixedu.domain.RootDomainObject")
&& (roleName.equals("rootDomainObject") || roleName.equals("rootDomainObjects"))) {
continue;
}
if (role.getMultiplicityUpper() != 1) {
// collection descriptors
if (classDescriptor.getCollectionDescriptorByName(roleName) == null) {
CollectionDescriptor collectionDescriptor = new CollectionDescriptor(classDescriptor);
if (role.getOtherRole().getMultiplicityUpper() == 1) {
String fkField = "oid" + StringUtils.capitalize(role.getOtherRole().getName());
ClassDescriptor otherClassDescriptor = (ClassDescriptor) ojbMetadata.get(((DomainClass) role
.getType()).getFullName());
if (otherClassDescriptor == null) {
System.out.println("Ignoring " + ((DomainClass) role.getType()).getFullName());
continue;
}
generateOneToManyCollectionDescriptor(collectionDescriptor, fkField);
} else {
generateManyToManyCollectionDescriptor(collectionDescriptor, role);
}
updateCollectionDescriptorWithCommonSettings(classDescriptor, persistentFieldClass, role, roleName,
collectionDescriptor);
}
}
}
domEntity = dClass.getSuperclass();
}
}
private static void updateCollectionDescriptorWithCommonSettings(final ClassDescriptor classDescriptor,
Class persistentFieldClass, Role role, String roleName, CollectionDescriptor collectionDescriptor)
throws ClassNotFoundException {
collectionDescriptor.setItemClass(Class.forName(role.getType().getFullName()));
collectionDescriptor.setPersistentField(new WriteOnlyPersistentField(persistentFieldClass, roleName));
collectionDescriptor.setRefresh(false);
collectionDescriptor.setCascadingStore(ObjectReferenceDescriptor.CASCADE_NONE);
collectionDescriptor.setCollectionClass(OJBFunctionalSetWrapper.class);
collectionDescriptor.setCascadeRetrieve(false);
collectionDescriptor.setLazy(false);
classDescriptor.addCollectionDescriptor(collectionDescriptor);
}
private static void generateManyToManyCollectionDescriptor(CollectionDescriptor collectionDescriptor, Role role) {
String indirectionTableName = DbUtil.convertToDBStyle(role.getRelation().getName());
String fkToItemClass = DbUtil.getFkName(role.getType().getName());
String fkToThisClass = DbUtil.getFkName(role.getOtherRole().getType().getName());
if (fkToItemClass.equals(fkToThisClass)) {
fkToItemClass = fkToItemClass + "_" + DbUtil.convertToDBStyle(role.getName());
fkToThisClass = fkToThisClass + "_" + DbUtil.convertToDBStyle(role.getOtherRole().getName());
}
collectionDescriptor.setIndirectionTable(indirectionTableName);
collectionDescriptor.addFkToItemClass(fkToItemClass);
collectionDescriptor.addFkToThisClass(fkToThisClass);
collectionDescriptor.setCascadingDelete(ObjectReferenceDescriptor.CASCADE_NONE);
}
private static void generateOneToManyCollectionDescriptor(CollectionDescriptor collectionDescriptor, String foreignKeyField) {
collectionDescriptor.addForeignKeyField(foreignKeyField);
}
}