Package com.inspiresoftware.lib.dto.geda.impl

Source Code of com.inspiresoftware.lib.dto.geda.impl.DTOSupportImpl

/*
* This code is distributed under The GNU Lesser General Public License (LGPLv3)
* Please visit GNU site for LGPLv3 http://www.gnu.org/copyleft/lesser.html
*
* Copyright Denis Pavlov 2009
* Web: http://www.genericdtoassembler.org
* SVN: https://svn.code.sf.net/p/geda-genericdto/code/trunk/
* SVN (mirror): http://geda-genericdto.googlecode.com/svn/trunk/
*/

package com.inspiresoftware.lib.dto.geda.impl;

import com.inspiresoftware.lib.dto.geda.DTOAdaptersRegistrar;
import com.inspiresoftware.lib.dto.geda.DTODSLRegistrar;
import com.inspiresoftware.lib.dto.geda.DTOSupport;
import com.inspiresoftware.lib.dto.geda.adapter.Adapters;
import com.inspiresoftware.lib.dto.geda.adapter.ExtensibleBeanFactory;
import com.inspiresoftware.lib.dto.geda.adapter.repository.AdaptersRepository;
import com.inspiresoftware.lib.dto.geda.annotations.Dto;
import com.inspiresoftware.lib.dto.geda.assembler.Assembler;
import com.inspiresoftware.lib.dto.geda.assembler.DTOAssembler;
import com.inspiresoftware.lib.dto.geda.dsl.Registries;
import com.inspiresoftware.lib.dto.geda.event.DTOEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Basic implementation of the DTOSupport interface that provides the connection point
* between Spring AOP and the GeDA assembler worlds.
*
* This particular implementation supports the following context listeners:
* onDtoAssembly - fired just before transfer takes place
* onEntityAssembly - fired just before transfer takes place
* onDtoAssembled - fired immediately after assembly
* onDtoFailed - fired immediately after failed assembly
* onEntityAssembled - fired immediately after assembly
* onEntityFailed - fired immediately after failed assembly
*
* All event listeners provided with the following context:
* listener.onEvent(context, DTO, Entity [, Throwable])
*
* <p/>
* User: denispavlov
* Date: Sep 27, 2011
* Time: 5:33:05 PM
*/
public class DTOSupportImpl implements DTOSupport, InitializingBean {

    private static final Logger LOG = LoggerFactory.getLogger(DTOSupportImpl.class);

    private ExtensibleBeanFactory beanFactory = Adapters.beanFactory();

    private DTOAdaptersRegistrar adaptersRegistrar;
    private DTODSLRegistrar dslRegistrar;

    private final AdaptersRepository dtoValueConverters = Adapters.adaptersRepository();
    private com.inspiresoftware.lib.dto.geda.dsl.Registry dslRegistry = Registries.registry(beanFactory);

    private DTOEventListener onDtoAssembly;
    private DTOEventListener onEntityAssembly;

    private DTOEventListener onDtoAssembled;
    private DTOEventListener onDtoFailed;
    private DTOEventListener onEntityAssembled;
    private DTOEventListener onEntityFailed;

    private final Map<Integer, Boolean> isClassAnnotatedCache = new ConcurrentHashMap<Integer, Boolean>();

    public void setBeanFactory(final ExtensibleBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        this.dslRegistry = Registries.registry(beanFactory);
    }

    public void setAdaptersRegistrar(final DTOAdaptersRegistrar adaptersRegistrar) {
        this.adaptersRegistrar = adaptersRegistrar;
    }

    public void setDslRegistrar(final DTODSLRegistrar dslRegistrar) {
        this.dslRegistrar = dslRegistrar;
    }

    public void afterPropertiesSet() throws Exception {
        this.registerCoreAdapters();
        this.registerDSLMappings();
    }

    /**
     * Extension hook to register mappings via DSL registry immediately after
     * bean construction.
     */
    protected void registerDSLMappings() {
        if (this.dslRegistrar != null) {
            this.dslRegistrar.registerMappings(this, this.dslRegistry);
        }
    }

    /**
     * Extension hook to register converters, retrievers and matchers immediately after
     * bean construction.
     */
    protected void registerCoreAdapters() {
        if (this.adaptersRegistrar != null) {
            this.adaptersRegistrar.registerAdapters(this);
        }
    }

    /** {@inheritDoc} */
    public <T> T assembleDto(final T dto, final Object entity, final String context) {
        return assembleDto(null, dto, entity, context);
    }

    /** {@inheritDoc} */
    public <T> T assembleDtoByKey(final String dtoKey, final Object entity, final String context) {
        final Object dto = this.beanFactory.get(dtoKey);
        if (dto == null) {
            throw new IllegalArgumentException("DTO factory has no class specified for key: " + dtoKey);
        }
        return (T) assembleDto(null, dto, entity, context);
    }

    /** {@inheritDoc} */
    public <T> T assembleDto(final String dtoFilter, final T dto, final Object entity, final String context) {
        final Class dtoClassFilter;
        if (dtoFilter == null) {
            dtoClassFilter = dto.getClass();
        } else {
            dtoClassFilter = this.beanFactory.getClazz(dtoFilter);
            if (dtoClassFilter == null) {
                throw new IllegalArgumentException("DTO factory has no class specified for key: " + dtoFilter);
            }
        }
        try {
            if (this.onDtoAssembly != null) {
                this.onDtoAssembly.onEvent(context, dto, entity);
            }

            if (isAnnotatedClass(dtoClassFilter)) {
                DTOAssembler.newAssembler(dtoClassFilter, entity.getClass())
                        .assembleDto(dto, entity, this.dtoValueConverters.getAll(), this.beanFactory);
            } else {
                DTOAssembler.newAssembler(dtoClassFilter, entity.getClass(), dslRegistry)
                        .assembleDto(dto, entity, this.dtoValueConverters.getAll(), this.beanFactory);
            }

            if (this.onDtoAssembled != null) {
                this.onDtoAssembled.onEvent(context, dto, entity);
            }
            return dto;
        } catch (final RuntimeException re) {
            if (this.onDtoFailed != null) {
                this.onDtoFailed.onEvent(context, dto, entity, re);

                LOG.error("Exception skipped by event listener", re);

                return null;
            }
            throw re; // re-throw
        }
    }

    /** {@inheritDoc} */
    public <T> T assembleDtoByKey(final String dtoFilter, final String dtoKey, final Object entity, final String context) {
        final Object dto = this.beanFactory.get(dtoKey);
        if (dto == null) {
            throw new IllegalArgumentException("DTO factory has no class specified for key: " + dtoKey);
        }
        return (T) assembleDto(dtoFilter, dto, entity, context);
    }

    /** {@inheritDoc} */
    public <T> void assembleDtos(final String keyDto, final Collection<T> dtos, final Collection entities, final String context) {
        assembleDtos(null, keyDto, dtos, entities, context);
    }

    /** {@inheritDoc} */
    public <T> void assembleDtos(final String dtoFilter, final String keyDto,
                                 final Collection<T> dtos, final Collection entities, final String context) {
        if (!CollectionUtils.isEmpty(entities)) {
            final Class dtoClassFilter;
            if (dtoFilter == null) {
                dtoClassFilter = this.beanFactory.getClazz(keyDto);
                if (dtoClassFilter == null) {
                    throw new IllegalArgumentException("DTO factory has no class specified for key: " + keyDto);
                }
            } else {
                dtoClassFilter = this.beanFactory.getClazz(dtoFilter);
                if (dtoClassFilter == null) {
                    throw new IllegalArgumentException("DTO factory has no class specified for key: " + dtoFilter);
                }
            }
            final Class entityClass = entities.iterator().next().getClass();

            final Assembler asm;
            if (isAnnotatedClass(dtoClassFilter)) {
                asm = DTOAssembler.newAssembler(dtoClassFilter, entityClass);
            } else {
                asm = DTOAssembler.newAssembler(dtoClassFilter, entityClass, dslRegistry);
            }

            for (final Object entity : entities) {
                final Object dto = this.beanFactory.get(keyDto);
                if (dto == null) {
                    throw new IllegalArgumentException("DTO factory has no class specified for key: " + keyDto);
                }
                try {
                    if (this.onDtoAssembly != null) {
                        this.onDtoAssembly.onEvent(context, dto, entity);
                    }
                    asm.assembleDto(dto, entity, this.dtoValueConverters.getAll(), this.beanFactory);
                    dtos.add((T) dto);
                    if (this.onDtoAssembled != null) {
                        this.onDtoAssembled.onEvent(context, dto, entity);
                    }
                } catch (final RuntimeException re) {
                    if (this.onDtoFailed != null) {
                        this.onDtoFailed.onEvent(context, dto, entity, re);

                        LOG.error("Exception skipped by event listener", re);

                        continue;
                    }
                    throw re; // re-throw
                }
            }
        }
    }

    /** {@inheritDoc} */
    public <T> T assembleEntity(final Object dto, final T entity, final String context) {
        return assembleEntity(null, dto, entity, context);
    }

    /** {@inheritDoc} */
    public <T> T assembleEntityByKey(final Object dto, final String entityKey, final String context) {
        final Object entity = this.beanFactory.get(entityKey);
        if (entity == null) {
            throw new IllegalArgumentException("DTO factory has no class specified for key: " + entityKey);
        }
        return (T) assembleEntity(null, dto, entity, context);
    }

    /** {@inheritDoc} */
    public <T> T assembleEntityByKey(final String dtoFilter, final Object dto, final String entityKey, final String context) {
        final Object entity = this.beanFactory.get(entityKey);
        if (entity == null) {
            throw new IllegalArgumentException("DTO factory has no class specified for key: " + entityKey);
        }
        return (T) assembleEntity(dtoFilter, dto, entity, context);
    }


    /** {@inheritDoc} */
    public <T> T assembleEntity(final String dtoFilter, final Object dto, final T entity, final String context) {

        final Class dtoClassFilter;
        if (dtoFilter == null) {
            dtoClassFilter = dto.getClass();
        } else {
            dtoClassFilter = this.beanFactory.getClazz(dtoFilter);
            if (dtoClassFilter == null) {
                throw new IllegalArgumentException("DTO factory has no class specified for key: " + dtoFilter);
            }
        }

        try {
            if (this.onEntityAssembly != null) {
                this.onEntityAssembly.onEvent(context, dto, entity);
            }

            if (isAnnotatedClass(dtoClassFilter)) {
                DTOAssembler.newAssembler(dtoClassFilter, entity.getClass())
                        .assembleEntity(dto, entity, this.dtoValueConverters.getAll(), this.beanFactory);
            } else {
                DTOAssembler.newAssembler(dtoClassFilter, entity.getClass(), dslRegistry)
                        .assembleEntity(dto, entity, this.dtoValueConverters.getAll(), this.beanFactory);
            }

            if (this.onEntityAssembled != null) {
                this.onEntityAssembled.onEvent(context, dto, entity);
            }
            return entity;
        } catch (final RuntimeException re) {
            if (this.onEntityFailed != null) {
                this.onEntityFailed.onEvent(context, dto, entity, re);

                LOG.error("Exception skipped by event listener", re);

                return null;
            }
            throw re; // re-throw
        }
    }

    /** {@inheritDoc} */
    public <T> void assembleEntities(final String entityKey, final Collection dtos, final Collection<T> entities, final String context) {
        assembleEntities(null, entityKey, dtos, entities, context);


    }

    /** {@inheritDoc} */
    public <T> void assembleEntities(final String dtoFilter, final String entityKey,
                                     final Collection dtos, final Collection<T> entities, final String context) {
        if (!CollectionUtils.isEmpty(dtos)) {
            final Class dtoClassFilter;
            if (dtoFilter == null) {
                dtoClassFilter = dtos.iterator().next().getClass();
            } else {
                dtoClassFilter = this.beanFactory.getClazz(dtoFilter);
                if (dtoClassFilter == null) {
                    throw new IllegalArgumentException("DTO factory has no class specified for key: " + dtoFilter);
                }
            }
            final Class entityClass =  this.beanFactory.getClazz(entityKey);
            if (entityClass == null) {
                throw new IllegalArgumentException("DTO factory has no class specified for key: " + entityKey);
            }

            final Assembler asm;
            if (isAnnotatedClass(dtoClassFilter)) {
                asm = DTOAssembler.newAssembler(dtoClassFilter, entityClass);
            } else {
                asm = DTOAssembler.newAssembler(dtoClassFilter, entityClass, dslRegistry);
            }

            for (final Object dto : dtos) {
                final Object entity = this.beanFactory.get(entityKey);
                if (entity == null) {
                    throw new IllegalArgumentException("DTO factory has no class specified for key: " + entityKey);
                }
                try {
                    if (this.onEntityAssembly != null) {
                        this.onEntityAssembly.onEvent(context, dto, entity);
                    }
                    asm.assembleEntity(dto, entity, this.dtoValueConverters.getAll(), this.beanFactory);
                    entities.add((T) entity);
                    if (this.onEntityAssembled != null) {
                        this.onEntityAssembled.onEvent(context, dto, entity);
                    }
                } catch (final RuntimeException re) {
                    if (this.onEntityFailed != null) {
                        this.onEntityFailed.onEvent(context, dto, entity, re);

                        LOG.error("Exception skipped by event listener", re);

                        continue;
                    }
                    throw re; // re-throw
                }
            }
        }
    }

    /** {@inheritDoc} */
    public void registerAdapter(final String key, final Object converter) {

        LOG.debug("Registering [{}] with key [{}]", converter, key);

        this.dtoValueConverters.registerAdapter(key, converter);
    }

    /**
     * @param onDtoAssembled listener  invoked after assembly
     */
    public void setOnDtoAssembled(final DTOEventListener onDtoAssembled) {
        this.onDtoAssembled = onDtoAssembled;
    }

    /**
     * @param onDtoFailed  listener invoked after failed assembly
     */
    public void setOnDtoFailed(final DTOEventListener onDtoFailed) {
        this.onDtoFailed = onDtoFailed;
    }

    /**
     * @param onEntityAssembled  listener invoked after assembly
     */
    public void setOnEntityAssembled(final DTOEventListener onEntityAssembled) {
        this.onEntityAssembled = onEntityAssembled;
    }

    /**
     * @param onEntityFailed  listener
     */
    public void setOnEntityFailed(final DTOEventListener onEntityFailed) {
        this.onEntityFailed = onEntityFailed;
    }

    /**
     * @param onDtoAssembly listener  invoked before assembly
     */
    public void setOnDtoAssembly(final DTOEventListener onDtoAssembly) {
        this.onDtoAssembly = onDtoAssembly;
    }

    /**
     * @param onEntityAssembly listener invoked before assembly
     */
    public void setOnEntityAssembly(final DTOEventListener onEntityAssembly) {
        this.onEntityAssembly = onEntityAssembly;
    }


    private Boolean isAnnotatedClass(final Class clazz) {
        final Integer classHash = Integer.valueOf(clazz.hashCode());
        Boolean isAnn;
        if (isClassAnnotatedCache.containsKey(classHash)) {
            isAnn = isClassAnnotatedCache.get(classHash);
        } else {
            isAnn = Boolean.valueOf(clazz.getAnnotation(Dto.class) != null);
            isClassAnnotatedCache.put(classHash, isAnn);
        }
        return isAnn;
    }

}
TOP

Related Classes of com.inspiresoftware.lib.dto.geda.impl.DTOSupportImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.