seava.j4e.presenter.converter.ReflookupResolver.java Source code

Java tutorial

Introduction

Here is the source code for seava.j4e.presenter.converter.ReflookupResolver.java

Source

/** 
 * DNet eBusiness Suite
 * Copyright: 2013 Nan21 Electronics SRL. All rights reserved.
 * Use is subject to license terms.
 */
package seava.j4e.presenter.converter;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;

import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import seava.j4e.api.annotation.DsField;
import seava.j4e.api.annotation.Param;
import seava.j4e.api.annotation.RefLookup;
import seava.j4e.api.annotation.RefLookups;
import seava.j4e.api.exceptions.BusinessException;
import seava.j4e.api.exceptions.ErrorCode;
import seava.j4e.api.model.IModelWithId;
import seava.j4e.presenter.AbstractPresenterBase;

/**
 * Delegate class to update the entity references from the the data-source
 * model, based on the {@link RefLookup} annotations at the data-source model.
 * 
 * @author amathe
 * 
 * @param <M>
 * @param <E>
 */
public class ReflookupResolver<M, E> extends AbstractPresenterBase {

    /**
     * Model (data-source) class
     */
    private Class<M> modelClass;

    /**
     * Entity class
     */
    private Class<E> entityClass;

    public ReflookupResolver(Class<M> modelClass, Class<E> entityClass) {
        super();
        this.modelClass = modelClass;
        this.entityClass = entityClass;
    }

    public void execute(M ds, E e, boolean isInsert, EntityManager em) throws Exception {
        if (this.modelClass.isAnnotationPresent(RefLookups.class)) {

            RefLookup[] refLookups = this.modelClass.getAnnotation(RefLookups.class).value();

            for (RefLookup rl : refLookups) {
                this.doRefLookup1(ds, e, rl, isInsert, em);
            }
        }
    }

    /**
     * Get the ds-field with the given name.
     * 
     * @param fieldName
     * @return
     * @throws Exception
     */
    private Field _getDsField(String fieldName) throws Exception {
        return ReflectionUtils.findField(this.modelClass, fieldName);
    }

    /**
     * Get the getter for the ds-field with the given name.
     * 
     * @param fieldName
     * @return
     * @throws Exception
     */
    private Method _getDsGetter(String fieldName) throws Exception {
        return ReflectionUtils.findMethod(this.modelClass, "get" + StringUtils.capitalize(fieldName));
    }

    /**
     * Get the setter for the ds-field with the given name.
     * 
     * @param fieldName
     * @return
     * @throws Exception
     */
    private Method _getDsSetter(String fieldName) throws Exception {
        return this.modelClass.getMethod("set" + StringUtils.capitalize(fieldName),
                this._getDsField(fieldName).getType());
    }

    /**
     * Get the value of the ds-field with the given name.
     * 
     * @param fieldName
     * @return
     * @throws Exception
     */
    private Object _getDsFieldValue(String fieldName, M ds) throws Exception {
        Method getter = this._getDsGetter(fieldName);
        return getter.invoke(ds, (Object[]) null);
    }

    /**
     * Get the entity-field with the given name.
     * 
     * @param fieldName
     * @return
     * @throws Exception
     */
    private Field _getEntityField(String fieldName) throws Exception {
        return ReflectionUtils.findField(this.entityClass, fieldName);
    }

    /**
     * Get the getter for the entity-field with the given name.
     * 
     * @param fieldName
     * @return
     * @throws Exception
     */
    private Method _getEntityGetter(String fieldName) throws Exception {
        return this.entityClass.getMethod("get" + StringUtils.capitalize(fieldName));
    }

    /**
     * Get the setter for the entity field with the given name.
     * 
     * @param fieldName
     * @return
     * @throws Exception
     */
    private Method _getEntitySetter(String fieldName) throws Exception {
        return this.entityClass.getMethod("set" + StringUtils.capitalize(fieldName),
                this._getEntityField(fieldName).getType());
    }

    /**
     * Get the value of the entity-field with the given name.
     * 
     * @param fieldName
     * @return
     * @throws Exception
     */
    private Object _getEntityFieldValue(String fieldName, E e) throws Exception {
        Method getter = this._getEntityGetter(fieldName);
        return getter.invoke(e, (Object[]) null);
    }

    /**
     * Do the actual work, update the reference field in the entity based on the
     * ref-lookup rule.
     * 
     * @param m
     * @param e
     * @param refLookup
     * @param isInsert
     * @throws Exception
     */
    private void doRefLookup1(M ds, E e, RefLookup refLookup, boolean isInsert, EntityManager em) throws Exception {

        String refIdDsFieldName = refLookup.refId();
        Object refIdDsFieldValue = this._getDsFieldValue(refIdDsFieldName, ds);
        String refEntityFieldName = null;
        Field refIdDsField = this._getDsField(refIdDsFieldName);

        if (!refIdDsField.isAnnotationPresent(DsField.class)) {
            throw new Exception("Field " + refIdDsFieldName
                    + " cannot be used as value for refId in @RefLookup annotation as it is not marked as @DsField ");
        } else {
            DsField dsFieldAnnotation = refIdDsField.getAnnotation(DsField.class);

            /* Obey the noInsert and noUpdate rules. */

            if ((isInsert && dsFieldAnnotation.noInsert()) || (!isInsert && dsFieldAnnotation.noUpdate())) {
                return;
            }

            String path = dsFieldAnnotation.path();
            if (path.indexOf('.') > 0) {
                // TODO: handle the deep references also ( a.b.c.id )
                refEntityFieldName = path.substring(0, path.indexOf('.'));
            } else {
                throw new Exception("Field " + refIdDsFieldName
                        + " cannot be used as value for refId in @RefLookup annotation as its path(`" + path
                        + "`) in @DsField is not a reference path.");
            }
        }

        Class<?> refClass = this._getEntityField(refEntityFieldName).getType();
        Object ref = this._getEntityFieldValue(refEntityFieldName, e);
        Method setter = this._getEntitySetter(refEntityFieldName);

        if (refIdDsFieldValue != null && !"".equals(refIdDsFieldValue)) {
            /*
             * if there is an ID now in DS which points to a different reference
             * as the one in the original entity then update it to the new one
             */
            if (ref == null || !((IModelWithId<?>) ref).getId().equals(refIdDsFieldValue)) {
                setter.invoke(e, em.find(refClass, refIdDsFieldValue));
            }
        } else {

            /*
             * If there is no ID given in DS for the reference, try to lookup an
             * entity based on the given named query which must be a query based
             * on an unique-key. The given fields as parameters for the
             * named-query must uniquely identify an entity.
             */

            boolean shouldTryToFindReference = true;
            String namedQueryName = refLookup.namedQuery();

            Map<String, Object> values = new HashMap<String, Object>();
            Map<String, Object> namedQueryParams = new HashMap<String, Object>();

            if (namedQueryName == null || namedQueryName.equals("")) {
                shouldTryToFindReference = false;
            } else {
                for (Param p : refLookup.params()) {
                    String paramName = p.name();
                    String fieldName = p.field();
                    String staticValue = p.value();

                    Object fieldValue = null;
                    if (staticValue != null && !"".equals(staticValue)) {
                        fieldValue = staticValue;
                    } else {
                        fieldValue = this._getDsFieldValue(fieldName, ds);
                    }

                    if (fieldValue == null || (fieldValue instanceof String && ((String) fieldValue).equals(""))) {
                        shouldTryToFindReference = false;
                        break;
                    } else {
                        values.put(fieldName, fieldValue);
                        namedQueryParams.put(paramName, fieldValue);
                    }
                }
            }

            if (shouldTryToFindReference) {

                Object theReference = null;
                try {
                    theReference = (findEntityService(refClass)).findByUk(namedQueryName, namedQueryParams);
                } catch (javax.persistence.NoResultException exception) {

                    StringBuffer sb = new StringBuffer();

                    for (Map.Entry<String, Object> entry : values.entrySet()) {
                        sb.append(" `" + entry.getKey() + "` = `" + entry.getValue() + "`");
                    }

                    throw new BusinessException(ErrorCode.G_RUNTIME_ERROR,
                            "Cannot find  `" + refClass.getSimpleName() + "` reference using " + sb.toString()
                                    + " for data-source `" + ds.getClass().getSimpleName() + "`");
                }
                setter.invoke(e, theReference);
                Method refIdFieldInDsSetter = this._getDsSetter(refIdDsFieldName);
                refIdFieldInDsSetter.invoke(ds, ((IModelWithId<?>) theReference).getId());
            } else {
                setter.invoke(e, (Object) null);
            }
        }
    }

}