package pt.ist.fenixframework.backend.jvstmojb.ojb; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; import pt.ist.fenixframework.backend.jvstmojb.repository.DbUtil; import pt.ist.fenixframework.backend.jvstmojb.repository.database.JDBCTypeMap; 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; /** * @author - Shezad Anavarali (shezad@ist.utl.pt) * */ public class OJBMetadataGenerator { private static final Logger logger = LoggerFactory.getLogger(OJBMetadataGenerator.class); public static void updateOJBMappingFromDomainModel(DomainModel domainModel) throws Exception { final DescriptorRepository descriptorRepository = MetadataManager.getInstance().getGlobalRepository(); @SuppressWarnings("unchecked") Map<String, ClassDescriptor> ojbMetadata = descriptorRepository.getDescriptorTable(); for (DomainClass domClass : domainModel.getDomainClasses()) { final String classname = domClass.getFullName(); 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 (DomainClass domClass : domainModel.getDomainClasses()) { final String classname = domClass.getFullName(); final Class<?> clazz = Class.forName(classname); final 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); } } } } private static void addClassExtentOfAncesterClassDescriptors(final Map<String, ClassDescriptor> ojbMetadata, final DomainEntity domainEntity, final Class<?> clazz) { if (domainEntity != null && domainEntity instanceof DomainClass) { final DomainClass domainClass = (DomainClass) domainEntity; final String ancesterClassname = domainClass.getFullName(); final ClassDescriptor classDescriptor = ojbMetadata.get(ancesterClassname); classDescriptor.addExtentClass(clazz); addClassExtentOfAncesterClassDescriptors(ojbMetadata, domainClass.getSuperclass(), clazz); } } public static String getExpectedTableName(final DomainClass domainClass) { if (domainClass.getSuperclass() == null) { 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<String, ClassDescriptor> ojbMetadata, final Class<?> persistentFieldClass) throws Exception { DomainEntity domEntity = domClass; int fieldID = 1; addPrimaryFieldDescriptor(domainModel, "oid", "long", fieldID++, classDescriptor, persistentFieldClass); // write the domainMetaObject for all domain objects addFieldDescriptor(domainModel, "oidDomainMetaObject", "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 = JDBCTypeMap.getJdbcTypeFor(domainModel, 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 = JDBCTypeMap.getJdbcTypeFor(domainModel, slotType); fieldDescriptor.setColumnType(sqlType); classDescriptor.addFieldDescriptor(fieldDescriptor); } } protected static void updateRelations(final ClassDescriptor classDescriptor, final DomainClass domClass, Map<String, ClassDescriptor> ojbMetadata, Class<?> persistentFieldClass) throws Exception { DomainEntity domEntity = domClass; while (domEntity instanceof DomainClass) { DomainClass dClass = (DomainClass) domEntity; // roles Iterator<Role> roleSlots = dClass.getRoleSlots(); while (roleSlots.hasNext()) { Role role = roleSlots.next(); String roleName = role.getName(); if (roleName == null) { 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 = ojbMetadata.get(((DomainClass) role.getType()).getFullName()); if (otherClassDescriptor == null) { logger.warn("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); } }