Package com.inspiresoftware.lib.dto.geda.assembler

Source Code of com.inspiresoftware.lib.dto.geda.assembler.DTOAssembler

/*
* 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.assembler;

import com.inspiresoftware.lib.dto.geda.assembler.annotations.AnnotationProxy;
import com.inspiresoftware.lib.dto.geda.assembler.annotations.impl.AnnotationProxies;
import com.inspiresoftware.lib.dto.geda.assembler.extension.Cache;
import com.inspiresoftware.lib.dto.geda.assembler.extension.MethodSynthesizer;
import com.inspiresoftware.lib.dto.geda.assembler.extension.impl.IntHashTable;
import com.inspiresoftware.lib.dto.geda.assembler.extension.impl.SoftReferenceCache;
import com.inspiresoftware.lib.dto.geda.dsl.Registry;
import com.inspiresoftware.lib.dto.geda.exception.*;

import java.util.Properties;
import java.util.WeakHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
* Assemble DTO and Entities depending on the annotations of Dto.
*
* @author Denis Pavlov
* @since 1.0.0
*
*/
@SuppressWarnings("unchecked")
public final class DTOAssembler {

  /**
   * String that defines key for synthesizer implementation to use.
   */
  public static final String SETTING_SYNTHESIZER_IMPL =
    "com.inspiresoftware.lib.dto.geda.assembler.DTOAssembler.SETTING_SYNTHESIZER_IMPL";

  /**
   * String that defines key for pattern for blacklisting entity class names.
   * E.g. Javasist implementation enhances classes by subclassing and adding _$$_javasist
   * prefix. This pattern will allow to detect these classes and look up parent class names
   * to overcome class cast exceptions.
   */
  public static final String SETTING_ENTITY_CLASS_NAME_BLACKLIST_PATTERN =
    "com.inspiresoftware.lib.dto.geda.assembler.DTOAssembler.SETTING_ENTITY_CLASS_NAME_BLACKLIST_PATTERN";
  private static final String SETTING_ENTITY_CLASS_NAME_BLACKLIST_PATTERN_DEFAULT = "_\\$\\$_";
  private static Pattern entityClassNameBlacklistPatternValue = Pattern.compile(SETTING_ENTITY_CLASS_NAME_BLACKLIST_PATTERN_DEFAULT);
 
  private static final WeakHashMap<ClassLoader, Cache<Assembler>> CL_CACHE = new WeakHashMap<ClassLoader, Cache<Assembler>>();

    private static final WeakHashMap<ClassLoader, MethodSynthesizer> CL_SYNTHESIZER = new WeakHashMap<ClassLoader, MethodSynthesizer>();

    private static final IntHashTable<Boolean> WHITELIST_ENTITIES = new IntHashTable<Boolean>();

    private static final IntHashTable<Class[]> AUTOBINDING = new IntHashTable<Class[]>();

  /**
   * Setup allows to configure some of the behaviour of GeDA. Currently it is used to tune the caching cleanup cycles.
   * There are two caches used in GeDA:
   * <ul>
   * <li>DTOAssembler cache - that caches the assemblers instances</li>
   * <li>Dynamic classes cache - that caches the instances of {@link com.inspiresoftware.lib.dto.geda.assembler.extension.DataReader}s
   * and {@link com.inspiresoftware.lib.dto.geda.assembler.extension.DataWriter}s</li>
   * </ul>
   *
   * @param props properties with key specified by DTOAssembler.SETTINGS_* keys
   *
   * @throws NumberFormatException if the number of cycles specified in properties cannot be converted to int.
   * @throws GeDAException if any of the configurations cause exception
   */
  public static void setup(final Properties props) throws NumberFormatException, GeDAException {
    final String synthesizerImpl = props.getProperty(SETTING_SYNTHESIZER_IMPL);
    final String classNameBlacklistPattern = props.getProperty(SETTING_ENTITY_CLASS_NAME_BLACKLIST_PATTERN);
    if (synthesizerImpl != null) {
            for (final MethodSynthesizer synthesizer : CL_SYNTHESIZER.values()) {
                synthesizer.configure("synthesizerImpl", synthesizerImpl);
            }
    }
    if (classNameBlacklistPattern != null) {
      entityClassNameBlacklistPatternValue = Pattern.compile(classNameBlacklistPattern);
    }
  }

  private static Class filterBlacklisted(final Class className) {
        final int hash = className.hashCode();
        if (!WHITELIST_ENTITIES.containsKey(hash)) {
            if (matches(className.getSimpleName())) {
                if (!className.getSuperclass().equals(Object.class)) {
                    // some proxies are derived straight from Object.class - we do not want those
                    return filterBlacklisted(className.getSuperclass());
                }
            } else {
                WHITELIST_ENTITIES.put(hash, Boolean.TRUE);
            }
        }
    return className;
  }
 
  /**
   * Exposed for testing.
   *
   * @param className entity class name
   * @return true if class name matches pattern, which will result in going one class level up.
   */
  static boolean matches(final String className) {
    final Matcher match = entityClassNameBlacklistPatternValue.matcher(className);
    return match.find();
  }

    private static Assembler getAssemblerFromCache(final ClassLoader cl, final int cacheKey) {
        if (CL_CACHE.containsKey(cl)) {
            return CL_CACHE.get(cl).get(cacheKey);
        }
        return null;
    }

    private static Assembler putAssemblerToCache(final ClassLoader cl, final int cacheKey, final Assembler asm) {
        Cache<Assembler> cache = CL_CACHE.get(cl);
        if (cache == null) {
            cache = new SoftReferenceCache<Assembler>();
            CL_CACHE.put(cl, cache);
        }
        cache.put(cacheKey, asm);
        return asm;
    }

  private static Assembler createNewAssembler(
                final Class< ? > dto,
                final Class< ? > entity,
                final ClassLoader classLoader,
                final Object synthesizer,
                final Registry registry)
      throws InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
             InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
             GeDARuntimeException, AnnotationDuplicateBindingException {

        if (synthesizer instanceof MethodSynthesizerProxy) {
            return new DTOtoEntityAssemblerImpl(dto, entity, classLoader, (MethodSynthesizer) synthesizer, registry);
        }
        return new DTOtoEntityAssemblerImpl(dto, entity, classLoader, new MethodSynthesizerProxy(classLoader, synthesizer), registry);
  }

  private static Assembler createNewAssembler(
                final Class< ? > dto,
                final Class< ? >[] entities,
                final ClassLoader classLoader,
                final Object synthesizer,
                final Registry registry)
      throws InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
             InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
             GeDARuntimeException, AnnotationDuplicateBindingException {

        if (synthesizer instanceof MethodSynthesizerProxy) {
            return new DTOtoEntitiesAssemblerDecoratorImpl(dto, entities, classLoader, (MethodSynthesizer) synthesizer, registry);
        }
        return new DTOtoEntitiesAssemblerDecoratorImpl(dto, entities, classLoader, new MethodSynthesizerProxy(classLoader, synthesizer), registry);
  }

    private static AnnotationProxy getDtoAnnotation(final Class<?> dto) {
        final AnnotationProxy ann = AnnotationProxies.getClassAnnotationProxy(dto);
        if (ann.annotationExists()) {
            return ann;
        }
        throw new AnnotationMissingException(dto.getCanonicalName());
    }


    private static AnnotationProxy getDtoAnnotationAuto(final Class<?> dto)
      throws AnnotationMissingException, AnnotationMissingAutobindingException {
    final AnnotationProxy ann = AnnotationProxies.getClassAnnotationProxy(dto);
        if (!ann.annotationExists()) {
            throw new AnnotationMissingException(dto.getCanonicalName());
        }
        final String[] auto = ann.getValue("value");
    if (auto == null || auto.length == 0) {
      throw new AnnotationMissingAutobindingException(dto.getCanonicalName());
    }
    return ann;
  }

  private static Class[] detectAutobinding(final Class< ? > dto)
      throws AutobindingClassNotFoundException {
        final int cacheKey = dto.hashCode();
        if (AUTOBINDING.containsKey(cacheKey)) {
            return AUTOBINDING.get(cacheKey);
        }
        final AnnotationProxy ann = getDtoAnnotationAuto(dto);
        final String[] auto = ann.getValue("value");
        final Class[] classes = new Class[auto.length];
        for (int i = 0; i < auto.length; i++) {
            final String clazz = auto[i];
            try {
                if (clazz == null || clazz.length() == 0) {
                    throw new AnnotationMissingAutobindingException(dto.getCanonicalName());
                }
                classes[i] = Class.forName(clazz, true, dto.getClassLoader());
            } catch (ClassNotFoundException cnfe) {
                throw new AutobindingClassNotFoundException(dto.getCanonicalName(), clazz);
            }
        }
        AUTOBINDING.put(cacheKey, classes);
        return classes;
  }

    private static MethodSynthesizer getDefaultSynthesizer(final ClassLoader classLoader) {
        MethodSynthesizer syn = CL_SYNTHESIZER.get(classLoader);
        if (syn == null) {
            syn = new MethodSynthesizerProxy(classLoader);
            CL_SYNTHESIZER.put(classLoader, syn);
        }
        return syn;
    }

    private static <DTO, Entity> int createAssemblerKey(
            final Class<DTO> dto,
            final Class<Entity> entity,
            final Object synthesizer,
            final Registry registry) {
        int result = dto.hashCode();
        result = 31 * result + entity.hashCode();
        result = 31 * result + synthesizer.hashCode();
        if (registry  != null) {
            result = 31 * result + registry.hashCode();
        }
        return result;
  }

  private static <DTO, Entity> int createAssemblerKey(
            final Class<DTO> dto,
            final Class<Entity>[] entities,
            final Object synthesizer,
            final Registry registry) {

        int result = dto.hashCode();
        for (final Class entity : entities) {
            result = 31 * result + entity.hashCode();
        }
        result = 31 * result + synthesizer.hashCode();
        if (registry  != null) {
            result = 31 * result + registry.hashCode();
        }
        return result;
  }


    /**
     * @param dto Dto concrete class that is annotated.
     * @param entity the entity class or interface that has appropriate getters and setters
     * @param synthesizer custom method synthesizer to use (see {@link com.inspiresoftware.lib.dto.geda.assembler.MethodSynthesizerProxy} )
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingException if dto class is missing the {@link com.inspiresoftware.lib.dto.geda.annotations.Dto} annotation.
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newCustomAssembler(
            final Class< ? > dto,
            final Class< ? > entity,
            final Object synthesizer)
        throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
            InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
            InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
            GeDARuntimeException, AnnotationDuplicateBindingException {

        return newCustomAssembler(dto, entity, DTOAssembler.class.getClassLoader(), synthesizer);
    }

  /**
   * @param dto Dto concrete class that is annotated.
   * @param entity the entity class or interface that has appropriate getters and setters
     * @param classLoader class loader for object graph serviced by this assembler
     * @param synthesizer custom method synthesizer to use (see {@link com.inspiresoftware.lib.dto.geda.assembler.MethodSynthesizerProxy} )
   * @return assembler instance for this conversion.
   *
   * @throws AnnotationMissingException if dto class is missing the {@link com.inspiresoftware.lib.dto.geda.annotations.Dto} annotation.
   * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
   * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
   * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
   * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
   * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
   * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
   * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
   * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
   * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
   * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
  public static Assembler newCustomAssembler(
      final Class< ? > dto,
            final Class< ? > entity,
            final ClassLoader classLoader,
            final Object synthesizer)
    throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
         InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
         InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
         GeDARuntimeException, AnnotationDuplicateBindingException {

        final Class< ? > realEntity = filterBlacklisted(entity);
        final int key = createAssemblerKey(dto, realEntity, synthesizer, null);

        final Assembler asm = getAssemblerFromCache(classLoader, key);
        if (asm != null) {
            return asm;
        }

        getDtoAnnotation(dto);

    return putAssemblerToCache(classLoader, key, createNewAssembler(dto, realEntity, classLoader, synthesizer, null));
  }

    /**
     * @param dto Dto concrete class that is annotated.
     * @param entity the entity class or interface that has appropriate getters and setters
     * @param registry DSL registry that contains all mappings
     * @param synthesizer custom method synthesizer to use (see {@link com.inspiresoftware.lib.dto.geda.assembler.MethodSynthesizerProxy} )
     * @return assembler instance for this conversion.
     *
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newCustomAssembler(
                final Class< ? > dto,
                final Class< ? > entity,
                final Registry registry,
                final Object synthesizer)
            throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                    InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                    InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                    GeDARuntimeException, AnnotationDuplicateBindingException {

        return newCustomAssembler(dto, entity, DTOAssembler.class.getClassLoader(), registry, synthesizer);
    }

  /**
   * @param dto Dto concrete class that is annotated.
   * @param entity the entity class or interface that has appropriate getters and setters
     * @param classLoader class loader for object graph serviced by this assembler
     * @param registry DSL registry that contains all mappings
     * @param synthesizer custom method synthesizer to use (see {@link com.inspiresoftware.lib.dto.geda.assembler.MethodSynthesizerProxy} )
   * @return assembler instance for this conversion.
   *
   * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
   * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
   * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
   * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
   * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
   * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
   * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
   * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
   * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
   * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
   */
  public static Assembler newCustomAssembler(
      final Class< ? > dto,
            final Class< ? > entity,
            final ClassLoader classLoader,
            final Registry registry,
            final Object synthesizer)
    throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
         InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
         InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
         GeDARuntimeException, AnnotationDuplicateBindingException {

        final Class< ? > realEntity = filterBlacklisted(entity);
        final int key = createAssemblerKey(dto, realEntity, synthesizer, registry);

        final Assembler asm = getAssemblerFromCache(classLoader, key);
        if (asm != null) {
            return asm;
        }

        if (registry == null) {
            throw new GeDARuntimeException("Registry cannot be null");
        }

        return putAssemblerToCache(classLoader, key, createNewAssembler(dto, realEntity, classLoader, synthesizer, registry));
  }

    /**
     * @param dto Dto concrete class that is annotated.
     * @param entities the entity classes or interfaces that have appropriate getters and setters
     * @param synthesizer custom method synthesizer to use (see {@link com.inspiresoftware.lib.dto.geda.assembler.MethodSynthesizerProxy} )
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingException if dto class is missing the {@link com.inspiresoftware.lib.dto.geda.annotations.Dto} annotation.
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newCustomCompositeAssembler(
                final Class< ? > dto,
                final Class< ? >[] entities,
                final Object synthesizer)
            throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                    InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                    InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                    GeDARuntimeException, AnnotationDuplicateBindingException {

        return newCustomCompositeAssembler(dto, entities, DTOAssembler.class.getClassLoader(), synthesizer);
    }

  /**
   * @param dto Dto concrete class that is annotated.
   * @param entities the entity classes or interfaces that have appropriate getters and setters
     * @param classLoader class loader for object graph serviced by this assembler
     * @param synthesizer custom method synthesizer to use (see {@link com.inspiresoftware.lib.dto.geda.assembler.MethodSynthesizerProxy} )
   * @return assembler instance for this conversion.
   *
   * @throws AnnotationMissingException if dto class is missing the {@link com.inspiresoftware.lib.dto.geda.annotations.Dto} annotation.
   * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
   * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
   * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
   * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
   * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
   * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
   * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
   * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
   * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
   * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
   */
  public static Assembler newCustomCompositeAssembler(
                final Class< ? > dto,
                final Class< ? >[] entities,
                final ClassLoader classLoader,
                final Object synthesizer)
            throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                   InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                   InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                   GeDARuntimeException, AnnotationDuplicateBindingException {

        getDtoAnnotation(dto);

    return createNewAssembler(dto, entities, classLoader, synthesizer, null);
  }

    /**
     * @param dto Dto concrete class that is annotated.
     * @param entity the entity class or interface that has appropriate getters and setters
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingException if dto class is missing the {@link com.inspiresoftware.lib.dto.geda.annotations.Dto} annotation.
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newAssembler(
                final Class< ? > dto,
                final Class< ? > entity)
            throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                    InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                    InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                    GeDARuntimeException, AnnotationDuplicateBindingException {

        return newAssembler(dto, entity, DTOAssembler.class.getClassLoader());
    }

    /**
     * @param dto Dto concrete class that is annotated.
     * @param entity the entity class or interface that has appropriate getters and setters
     * @param classLoader class loader for object graph serviced by this assembler
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingException if dto class is missing the {@link com.inspiresoftware.lib.dto.geda.annotations.Dto} annotation.
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newAssembler(
                final Class< ? > dto,
                final Class< ? > entity,
                final ClassLoader classLoader)
            throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                   InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                   InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                   GeDARuntimeException, AnnotationDuplicateBindingException {

        final Class< ? > realEntity = filterBlacklisted(entity);
        final MethodSynthesizer synthesizer = getDefaultSynthesizer(classLoader);
        final int key = createAssemblerKey(dto, realEntity, synthesizer, null);

        final Assembler asm = getAssemblerFromCache(classLoader, key);
        if (asm != null) {
            return asm;
        }

        getDtoAnnotation(dto);

      return putAssemblerToCache(classLoader, key, createNewAssembler(dto, realEntity, classLoader, synthesizer, null));
    }

    /**
     * @param dto Dto concrete class that is annotated.
     * @param entity the entity class or interface that has appropriate getters and setters
     * @param registry DSL registry that contains all mappings
     * @return assembler instance for this conversion.
     *
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newAssembler(
                final Class< ? > dto,
                final Class< ? > entity,
                final Registry registry)
            throws InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                    InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                    InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                    GeDARuntimeException, AnnotationDuplicateBindingException {

        return newAssembler(dto, entity, DTOAssembler.class.getClassLoader(), registry);
    }

    /**
     * @param dto Dto concrete class that is annotated.
     * @param entity the entity class or interface that has appropriate getters and setters
     * @param classLoader class loader for object graph serviced by this assembler
     * @param registry DSL registry that contains all mappings
     * @return assembler instance for this conversion.
     *
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newAssembler(
                final Class< ? > dto,
                final Class< ? > entity,
                final ClassLoader classLoader,
                final Registry registry)
            throws InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                   InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                   InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                   GeDARuntimeException, AnnotationDuplicateBindingException {

        final Class< ? > realEntity = filterBlacklisted(entity);
        final MethodSynthesizer synthesizer = getDefaultSynthesizer(classLoader);
        final int key = createAssemblerKey(dto, realEntity, synthesizer, registry);

        final Assembler asm = getAssemblerFromCache(classLoader, key);
        if (asm != null) {
            return asm;
        }

        if (registry == null) {
        throw new GeDARuntimeException("Registry cannot be null");
      }

      return putAssemblerToCache(classLoader, key, createNewAssembler(dto, realEntity, classLoader, synthesizer, registry));
    }

    /**
     * @param dto Dto concrete class that is annotated.
     * @param entities the entity classes or interfaces that has appropriate getters and setters
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingException if dto class is missing the {@link com.inspiresoftware.lib.dto.geda.annotations.Dto} annotation.
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newCompositeAssembler(
                final Class< ? > dto,
                final Class< ? >[] entities)
            throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                    InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                    InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                    GeDARuntimeException, AnnotationDuplicateBindingException {

        return newCompositeAssembler(dto, entities, DTOAssembler.class.getClassLoader());

    }

    /**
     * @param dto Dto concrete class that is annotated.
     * @param entities the entity classes or interfaces that has appropriate getters and setters
     * @param classLoader class loader for object graph serviced by this assembler
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingException if dto class is missing the {@link com.inspiresoftware.lib.dto.geda.annotations.Dto} annotation.
     * @throws InspectionInvalidDtoInstanceException if dto instance used for read/write operation is not valid
     * @throws InspectionInvalidEntityInstanceException if entity instance used for read/write operation is not valid
     * @throws AnnotationDuplicateBindingException if during mapping scan same dto field is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newCompositeAssembler(
                final Class< ? > dto,
                final Class< ? >[] entities,
                final ClassLoader classLoader)
            throws AnnotationMissingException, InspectionInvalidDtoInstanceException, InspectionInvalidEntityInstanceException,
                   InspectionScanningException, UnableToCreateInstanceException, InspectionPropertyNotFoundException,
                   InspectionBindingNotFoundException, AnnotationMissingBindingException, AnnotationValidatingBindingException,
                   GeDARuntimeException, AnnotationDuplicateBindingException {

        final MethodSynthesizer synthesizer = getDefaultSynthesizer(classLoader);
        final int key = createAssemblerKey(dto, entities, synthesizer, null);

        final Assembler asm = getAssemblerFromCache(classLoader, key);
        if (asm != null) {
            return asm;
        }

        getDtoAnnotation(dto);

      return putAssemblerToCache(classLoader, key, createNewAssembler(dto, entities, classLoader, synthesizer, null));
    }

    /**
     * @param dto Dto concrete class that is annotated and value attribute of Dto is supplied.
     * @param synthesizer custom method synthesizer to use (see {@link com.inspiresoftware.lib.dto.geda.assembler.MethodSynthesizerProxy} )
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingAutobindingException if autobinding parameter is missing
     * @throws AutobindingClassNotFoundException if class specified for auto binding cannot be found
     * @throws AnnotationDuplicateBindingException if same field name is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newCustomAssembler(
                final Class< ? > dto,
                final Object synthesizer)
            throws AnnotationMissingAutobindingException, AutobindingClassNotFoundException, InspectionScanningException,
                    UnableToCreateInstanceException, InspectionPropertyNotFoundException, InspectionBindingNotFoundException,
                    AnnotationMissingBindingException, AnnotationValidatingBindingException, GeDARuntimeException,
                    AnnotationDuplicateBindingException  {

        return newCustomAssembler(dto, DTOAssembler.class.getClassLoader(), synthesizer);

    }

    /**
     * @param dto Dto concrete class that is annotated and value attribute of Dto is supplied.
     * @param classLoader class loader for object graph serviced by this assembler
     * @param synthesizer custom method synthesizer to use (see {@link com.inspiresoftware.lib.dto.geda.assembler.MethodSynthesizerProxy} )
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingAutobindingException if autobinding parameter is missing
     * @throws AutobindingClassNotFoundException if class specified for auto binding cannot be found
     * @throws AnnotationDuplicateBindingException if same field name is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newCustomAssembler(
                final Class< ? > dto,
                final ClassLoader classLoader,
                final Object synthesizer)
            throws AnnotationMissingAutobindingException, AutobindingClassNotFoundException, InspectionScanningException,
                   UnableToCreateInstanceException, InspectionPropertyNotFoundException, InspectionBindingNotFoundException,
                   AnnotationMissingBindingException, AnnotationValidatingBindingException, GeDARuntimeException,
                   AnnotationDuplicateBindingException  {

        final Class[] classes = detectAutobinding(dto);

        final int key = createAssemblerKey(dto, classes, synthesizer, null);

        final Assembler asm = getAssemblerFromCache(classLoader, key);
        if (asm != null) {
            return asm;
        }

        if (classes.length == 1) {
            return putAssemblerToCache(classLoader, key, createNewAssembler(dto, classes[0], classLoader, synthesizer, null));
        }
    return putAssemblerToCache(classLoader, key, createNewAssembler(dto, classes, classLoader, synthesizer, null));

    }

    /**
     * @param dto Dto concrete class that is annotated and value attribute of Dto is supplied.
     * @return assembler instance for this conversion.
     *
     * @throws AnnotationMissingAutobindingException if autobinding parameter is missing
     * @throws AutobindingClassNotFoundException if class specified for auto binding cannot be found
     * @throws AnnotationDuplicateBindingException if same field name is mapped more than once
     * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
     */
    public static Assembler newAssembler(
                final Class< ? > dto)
            throws AnnotationMissingAutobindingException, AutobindingClassNotFoundException, InspectionScanningException,
                    UnableToCreateInstanceException, InspectionPropertyNotFoundException, InspectionBindingNotFoundException,
                    AnnotationMissingBindingException, AnnotationValidatingBindingException, GeDARuntimeException,
                    AnnotationDuplicateBindingException  {

        return newAssembler(dto, DTOAssembler.class.getClassLoader());
    }

  /**
   * @param dto Dto concrete class that is annotated and value attribute of Dto is supplied.
     * @param classLoader class loader for object graph serviced by this assembler
     * @return assembler instance for this conversion.
   *
   * @throws AnnotationMissingAutobindingException if autobinding parameter is missing
   * @throws AutobindingClassNotFoundException if class specified for auto binding cannot be found
   * @throws AnnotationDuplicateBindingException if same field name is mapped more than once
   * @throws GeDARuntimeException unhandled cases - this is (if GeDA was not tampered with) means library failure and should be reported
     * @throws AnnotationValidatingBindingException in case binding create has a mismatching return type/parameters
     * @throws AnnotationMissingBindingException in case when no valid property on entity is specified to bind to
     * @throws InspectionBindingNotFoundException in case when no valid property on entity is found to bind to
     * @throws InspectionPropertyNotFoundException in case a binding field cannot be found
     * @throws UnableToCreateInstanceException if an instance of an auto created class (one that is directly created by GeDA) cannot be instantiated
     * @throws InspectionScanningException general error that may occur during scanning a class for fields and method descriptors
   */
  public static Assembler newAssembler(
                final Class< ? > dto,
                final ClassLoader classLoader)
            throws AnnotationMissingAutobindingException, AutobindingClassNotFoundException, InspectionScanningException,
                   UnableToCreateInstanceException, InspectionPropertyNotFoundException, InspectionBindingNotFoundException,
                   AnnotationMissingBindingException, AnnotationValidatingBindingException, GeDARuntimeException,
                   AnnotationDuplicateBindingException  {

        final Class[] classes = detectAutobinding(dto);

        final MethodSynthesizer synthesizer = getDefaultSynthesizer(classLoader);
        final int key = createAssemblerKey(dto, classes, synthesizer, null);

        final Assembler asm = getAssemblerFromCache(classLoader, key);
        if (asm != null) {
            return asm;
        }

        if (classes.length == 1) {
            return putAssemblerToCache(classLoader, key, createNewAssembler(dto, classes[0], classLoader, synthesizer, null));
        }

    return putAssemblerToCache(classLoader, key, createNewAssembler(dto, classes, classLoader, synthesizer, null));
  }


    /**
     * Dispose of all GeDA caches and references for given class loader.
     * This is useful when you wish to unload a particular module of your
     * application and ensure no memory leaks occur. An example use would be
     * undeploying an OSGi bundle.
     *
     * @param classLoader class loader to clean references for
     */
    public static void disposeOfDtoAssemblersBy(final ClassLoader classLoader) {

        if (classLoader != null) {
            final Cache<Assembler> cache = CL_CACHE.get(classLoader);
            if (cache != null) {
                cache.releaseResources();
                CL_CACHE.remove(classLoader);
            }
        }
    }


}
TOP

Related Classes of com.inspiresoftware.lib.dto.geda.assembler.DTOAssembler

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.