Search in sources :

Example 1 with MappingFilter

use of org.jaffa.beans.moulding.mapping.MappingFilter in project jaffa-framework by jaffa-projects.

the class BeanMoulder method moldFromDomain.

/**
 * Mould data from domain object and its related objects into a new JavaBean based
 * domain object graph, based on the defined mapping rules.
 * @param source Source object to mould data from, typically extends Persistent
 * @param target Target object to mould data to, typically extends DomainDAO
 * @param graph The mapping class with the rules of how to map this source object
 * @param filter Filter object that it is used to control what fields are populated or the target objects
 * @param objectPath  The path of this object being processed. This identifies possible parent
 * and/or indexed entries where this object is contained.
 * @param includeKeys true if key fields should be included in results regardless of the filters
 * @throws ApplicationExceptions Thrown if one or more application logic errors are generated during moulding
 * @throws FrameworkException Thrown if any runtime moulding error has occured.
 */
public static void moldFromDomain(Object source, Object target, GraphMapping graph, MappingFilter filter, String objectPath, boolean includeKeys) throws ApplicationExceptions, FrameworkException {
    if (graph == null)
        graph = MappingFactory.getInstance(target);
    // throw new InstantiationException("A GraphMapping must be supplied");
    if (filter == null)
        filter = new MappingFilter(graph);
    try {
        // get list of target fileds to populate
        String[] tFields = graph.getDataFieldNames();
        if (tFields != null && tFields.length != 0)
            for (int i = 0; i < tFields.length; i++) {
                // Try to map a source to a target
                String tName = tFields[i];
                String fullName = tName;
                if (objectPath != null)
                    fullName = objectPath + "." + fullName;
                if (filter == null || filter.isFieldIncluded(fullName) || (includeKeys && graph.isKeyField(tName))) {
                    String sName = graph.getDomainFieldName(tName);
                    PropertyDescriptor tDesc = graph.getDataFieldDescriptor(tName);
                    PropertyDescriptor sDesc = graph.getDomainFieldDescriptor(tName);
                    // DAO descriptor with a setter, and a DO descriptor with a getter
                    if (sDesc == null)
                        log.error("No Getter for " + tName + " in path " + fullName);
                    // incase getter is not public, make it available
                    Method sm = sDesc.getReadMethod();
                    if (!sm.isAccessible())
                        sm.setAccessible(true);
                    // get the setter, and make is available if needed
                    Method tm = tDesc.getWriteMethod();
                    if (!tm.isAccessible())
                        tm.setAccessible(true);
                    // Set the value if the source and target are the same datatype
                    Class tClass = tDesc.getPropertyType();
                    Class sClass = sDesc.getPropertyType();
                    if (tClass.isAssignableFrom(sClass)) {
                        // Get the value being copied
                        Object sValue = sm.invoke(source, (Object[]) null);
                        if (sValue != null) {
                            tm.invoke(target, new Object[] { sValue });
                            log.debug("Set " + tName + " = " + sValue);
                        } else
                            log.debug(tName + " no set, NULL value");
                    // See if there is a datatype mapper for these classes
                    } else if (DataTypeMapper.instance().isMappable(sClass, tClass)) {
                        // Get the value being copied
                        Object sValue = sm.invoke(source, (Object[]) null);
                        if (sValue != null) {
                            sValue = DataTypeMapper.instance().map(sValue, tClass);
                            tm.invoke(target, new Object[] { sValue });
                            log.debug("Set " + tName + " = " + sValue);
                        } else
                            log.debug(tName + " no set, NULL value");
                    // See if target is a DAO, this could be a foreign object or one-to-one relationship...
                    } else if (DomainDAO.class.isAssignableFrom(tClass) && IPersistent.class.isAssignableFrom(sClass)) {
                        // Get the mapper for the related DAO, if it has keys, it must be a foriegn object
                        if (graph.isForeignField(tName)) {
                            // look at foreign key fields, and make sure they are not null
                            List foreignKeys = graph.getForeignKeys(tName);
                            List foreignKeyValues = new ArrayList();
                            boolean nullKey = false;
                            for (Iterator k = foreignKeys.iterator(); k.hasNext(); ) {
                                String doProp = (String) k.next();
                                Object value = null;
                                PropertyDescriptor doPd = graph.getRealDomainFieldDescriptor(doProp);
                                if (doPd != null && doPd.getReadMethod() != null) {
                                    Method m = doPd.getReadMethod();
                                    if (!m.isAccessible())
                                        m.setAccessible(true);
                                    value = m.invoke(source, new Object[] {});
                                    if (value == null)
                                        nullKey = true;
                                    foreignKeyValues.add(value);
                                } else {
                                    throw new MouldException(MouldException.INVALID_FK_MAPPING, objectPath, doProp, graph.getDomainClassShortName());
                                }
                            }
                            if (nullKey) {
                                log.debug("Did not create skeleton object '" + tClass.getName() + "': one or more foreign key values missing.");
                            } else {
                                // Create the foreign object
                                log.debug("Creating foreign object - " + tClass.getName());
                                Object newDAO = newDAO(tClass);
                                boolean createSkeleton = true;
                                // Only retrieve related domain object and introspect if need
                                if (filter.areSubFieldsIncluded(fullName)) {
                                    // read object and introspect all
                                    log.debug("Read foreign object '" + fullName + "' and mold");
                                    try {
                                        Object sValue = sm.invoke(source, (Object[]) null);
                                        if (sValue != null) {
                                            BeanMoulder.moldFromDomain(sValue, newDAO, null, filter, fullName, true);
                                            createSkeleton = false;
                                        }
                                    } catch (InvocationTargetException e) {
                                        // If the foreign object is not found, warn and create the skeleton
                                        if (e.getCause() != null && e.getCause() instanceof InvalidForeignKeyException)
                                            log.warn("All foreign keys present, but foreign object does not exist");
                                        else
                                            throw e;
                                    }
                                }
                                if (createSkeleton) {
                                    // just set foreign keys from current object
                                    log.debug("Set keys on skeleton foreign object only");
                                    GraphMapping graph2 = MappingFactory.getInstance(newDAO);
                                    Set keys = graph2.getKeyFields();
                                    if (keys == null || keys.size() != foreignKeyValues.size()) {
                                        throw new MouldException(MouldException.MISMATCH_FK_MAPPING, objectPath, target.getClass().getName(), newDAO.getClass().getName());
                                    }
                                    int k2 = 0;
                                    // Look through all the foreign keys on the skeleton object
                                    for (Iterator k = keys.iterator(); k.hasNext(); k2++) {
                                        String keyField = (String) k.next();
                                        Object keyValue = foreignKeyValues.get(k2);
                                        PropertyDescriptor pd = graph2.getDataFieldDescriptor(keyField);
                                        if (pd != null && pd.getWriteMethod() != null) {
                                            Method m = pd.getWriteMethod();
                                            if (!m.isAccessible())
                                                m.setAccessible(true);
                                            m.invoke(newDAO, new Object[] { keyValue });
                                        } else {
                                            throw new MouldException(MouldException.CANT_SET_KEY_FIELD, objectPath, keyField, newDAO.getClass().getName());
                                        }
                                    }
                                }
                                tm.invoke(target, new Object[] { newDAO });
                                log.debug("Set " + tName + " = " + newDAO);
                            }
                        } else {
                            // This is not a foreign object, must be a related object
                            if (filter.areSubFieldsIncluded(fullName)) {
                                // Create the related object
                                log.debug("Creating One-To-One object - " + tClass.getName());
                                Object newDAO = newDAO(tClass);
                                // read object and introspect all
                                log.debug("Read related object '" + fullName + "' and mold");
                                Object sValue = sm.invoke(source, (Object[]) null);
                                if (sValue != null) {
                                    BeanMoulder.moldFromDomain(sValue, newDAO, null, filter, fullName, true);
                                } else {
                                    log.debug("Related object '" + fullName + "' not found. Ignore it!");
                                }
                                tm.invoke(target, new Object[] { newDAO });
                                log.debug("Set " + tName + " = " + newDAO);
                            } else
                                log.debug("No subfields for object " + fullName + " included. Object not retrieved");
                        }
                    // END-related object
                    // See if Target may be an array of DAO's
                    } else if (tClass.isArray() && DomainDAO.class.isAssignableFrom(tClass.getComponentType()) && filter.areSubFieldsIncluded(fullName)) {
                        log.debug("Target is an array of DAO's");
                        log.debug("Read related objects '" + fullName + "' and mold");
                        Object sValue = sm.invoke(source, (Object[]) null);
                        if (sClass.isArray() && IPersistent.class.isAssignableFrom(sClass.getComponentType())) {
                            log.debug("Source is an array of Persistent Objects");
                            Object[] sArray = (Object[]) sValue;
                            if (sArray.length > 0) {
                                Object[] tArray = (Object[]) Array.newInstance(tClass.getComponentType(), sArray.length);
                                log.debug("Translate Array of Size " + sArray.length);
                                for (int j = 0; j < sArray.length; j++) {
                                    Object newDAO = newDAO(tClass.getComponentType());
                                    BeanMoulder.moldFromDomain(sArray[j], newDAO, null, filter, fullName, false);
                                    tArray[j] = newDAO;
                                    log.debug("Add to array [" + j + "] : " + newDAO);
                                }
                                tm.invoke(target, new Object[] { (Object) tArray });
                                log.debug("Set Array " + tName);
                            } else
                                log.debug("Source Array is empty! Do Nothing");
                        }
                    // source is DO array
                    // Error... No way to map property
                    } else {
                        String err = "Can't Mold Property " + fullName + " from " + sClass.getName() + " to " + tClass.getName();
                        log.error(err);
                        throw new RuntimeException(err);
                    }
                }
            // is included in filtered fields
            }
        // Clear changed fields on updated DAO
        if (target != null && target instanceof DomainDAO)
            ((DomainDAO) target).clearChanges();
    } catch (IllegalAccessException e) {
        MouldException me = new MouldException(MouldException.ACCESS_ERROR, objectPath, e.getMessage());
        log.error(me.getLocalizedMessage(), e);
        throw me;
    } catch (InvocationTargetException e) {
        if (e.getCause() != null) {
            if (e.getCause() instanceof FrameworkException)
                throw (FrameworkException) e.getCause();
            if (e.getCause() instanceof ApplicationExceptions)
                throw (ApplicationExceptions) e.getCause();
            if (e.getCause() instanceof ApplicationException) {
                ApplicationExceptions aes = new ApplicationExceptions();
                aes.add((ApplicationException) e.getCause());
                throw aes;
            }
        }
        MouldException me = new MouldException(MouldException.INVOCATION_ERROR, objectPath, e);
        log.error(me.getLocalizedMessage(), me.getCause());
        throw me;
    } catch (InstantiationException e) {
        MouldException me = new MouldException(MouldException.INSTANTICATION_ERROR, objectPath, e.getMessage());
        log.error(me.getLocalizedMessage(), e);
        throw me;
    }
}
Also used : Set(java.util.Set) ArrayList(java.util.ArrayList) MappingFilter(org.jaffa.beans.moulding.mapping.MappingFilter) IPersistent(org.jaffa.persistence.IPersistent) Iterator(java.util.Iterator) DomainDAO(org.jaffa.beans.moulding.data.domain.DomainDAO) ArrayList(java.util.ArrayList) List(java.util.List) ApplicationExceptions(org.jaffa.exceptions.ApplicationExceptions) PropertyDescriptor(java.beans.PropertyDescriptor) FrameworkException(org.jaffa.exceptions.FrameworkException) InvalidForeignKeyException(org.jaffa.datatypes.exceptions.InvalidForeignKeyException) Method(java.lang.reflect.Method) InvocationTargetException(java.lang.reflect.InvocationTargetException) ApplicationException(org.jaffa.exceptions.ApplicationException) GraphMapping(org.jaffa.beans.moulding.mapping.GraphMapping)

Aggregations

PropertyDescriptor (java.beans.PropertyDescriptor)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 Method (java.lang.reflect.Method)1 ArrayList (java.util.ArrayList)1 Iterator (java.util.Iterator)1 List (java.util.List)1 Set (java.util.Set)1 DomainDAO (org.jaffa.beans.moulding.data.domain.DomainDAO)1 GraphMapping (org.jaffa.beans.moulding.mapping.GraphMapping)1 MappingFilter (org.jaffa.beans.moulding.mapping.MappingFilter)1 InvalidForeignKeyException (org.jaffa.datatypes.exceptions.InvalidForeignKeyException)1 ApplicationException (org.jaffa.exceptions.ApplicationException)1 ApplicationExceptions (org.jaffa.exceptions.ApplicationExceptions)1 FrameworkException (org.jaffa.exceptions.FrameworkException)1 IPersistent (org.jaffa.persistence.IPersistent)1